Jump to content

Module:College color: Difference between revisions

From Wikipedia, the free encyclopedia
Content deleted Content added
revert to the last version before any attempted dark mode fixes until all issues can be addressed
yet another attempted dark mode fix
Tag: Reverted
Line 1: Line 1:
--
--
-- This module implements {{CollegePrimaryHex}}, {{CollegePrimaryStyle}},
-- This module implements {{CollegePrimaryHex}}, {{CollegePrimaryStyle}},
-- {{CollegeSecondaryHex}}, {{CollegeSecondaryStyle}}, {{CollegeSecondaryColorLink}}, and {{NCAA color}}
-- {{CollegePrimaryColorLink}}, {{CollegeSecondaryHex}},
-- {{CollegeSecondaryStyle}}, {{CollegeSecondaryColorLink}}, and {{NCAA color}}
--
--
local p = {}
local p = {}
Line 21: Line 20:
return 'box-shadow: ' .. s .. ';'
return 'box-shadow: ' .. s .. ';'
end
end
local function sRGB ( v )
local function sRGB(v)
if (v <= 0.03928) then
if (v <= 0.03928) then
v = v / 12.92
v = v / 12.92
else
else
v = math.pow((v+0.055)/1.055, 2.4)
v = math.pow((v + 0.055) / 1.055, 2.4)
end
end
return v
return v
end
end
local function color2lum( origc )
local function color2lum(origc)
local c = stripwhitespace(origc or ''):lower()
local c = stripwhitespace(origc or ''):lower()

-- remove leading # (if there is one)
c = mw.ustring.match(c, '^[#]*([a-f0-9]*)$')
c = mw.ustring.match(c, '^[#]*([a-f0-9]*)$')

-- split into rgb
local cs = mw.text.split(c or '', '')
local cs = mw.text.split(c or '', '')
if( #cs == 6 ) then
if (#cs == 6) then
local R = sRGB( (16*tonumber('0x' .. cs[1]) + tonumber('0x' .. cs[2]))/255 )
local R = sRGB((16 * tonumber('0x' .. cs[1]) + tonumber('0x' .. cs[2])) / 255)
local G = sRGB( (16*tonumber('0x' .. cs[3]) + tonumber('0x' .. cs[4]))/255 )
local G = sRGB((16 * tonumber('0x' .. cs[3]) + tonumber('0x' .. cs[4])) / 255)
local B = sRGB( (16*tonumber('0x' .. cs[5]) + tonumber('0x' .. cs[6]))/255 )
local B = sRGB((16 * tonumber('0x' .. cs[5]) + tonumber('0x' .. cs[6])) / 255)

return 0.2126 * R + 0.7152 * G + 0.0722 * B
return 0.2126 * R + 0.7152 * G + 0.0722 * B
elseif ( #cs == 3 ) then
elseif (#cs == 3) then
local R = sRGB( (16*tonumber('0x' .. cs[1]) + tonumber('0x' .. cs[1]))/255 )
local R = sRGB((16 * tonumber('0x' .. cs[1]) + tonumber('0x' .. cs[1])) / 255)
local G = sRGB( (16*tonumber('0x' .. cs[2]) + tonumber('0x' .. cs[2]))/255 )
local G = sRGB((16 * tonumber('0x' .. cs[2]) + tonumber('0x' .. cs[2])) / 255)
local B = sRGB( (16*tonumber('0x' .. cs[3]) + tonumber('0x' .. cs[3]))/255 )
local B = sRGB((16 * tonumber('0x' .. cs[3]) + tonumber('0x' .. cs[3])) / 255)

return 0.2126 * R + 0.7152 * G + 0.0722 * B
return 0.2126 * R + 0.7152 * G + 0.0722 * B
end
end

-- failure
error('Invalid hex color ' .. origc, 2)
error('Invalid hex color ' .. origc, 2)
end
end


local function remove_sport(team)
local function remove_sport(team)
team = mw.ustring.gsub(team, "%s*<[Bb][Rr][^<>]*>%s*", ' ');
team = mw.ustring.gsub(team, "%s*<[Bb][Rr][^<>]*>%s*", ' ')
team = mw.ustring.gsub(team, " [Tt]eam$", '')
team = mw.ustring.gsub(team, " [Tt]eam$", '')
team = mw.ustring.gsub(team, " [Bb]asketball$", '')
team = mw.ustring.gsub(team, " [Bb]asketball$", '')
Line 78: Line 69:
team = mw.ustring.gsub(team, " [Ww]omen's$", '')
team = mw.ustring.gsub(team, " [Ww]omen's$", '')
team = mw.ustring.gsub(team, " [Mm]en's$", '')
team = mw.ustring.gsub(team, " [Mm]en's$", '')

return team
return team
end
end

local function get_colors(team, unknown)
local function get_colors(team, unknown)
team = stripwhitespace(team or '')
team = stripwhitespace(team or '')
unknown = unknown or {"DCDCDC", "000000"}
unknown = unknown or {"DCDCDC", "000000"}

local use_default = {
local use_default = {
[""] = 1,
[""] = 1,
Line 90: Line 80:
["free agent"] = 1,
["free agent"] = 1,
}
}

local colors = nil
local colors = nil
if (team and use_default[team:lower()]) then

if ( team and use_default[team:lower()] ) then
colors = {"DCDCDC", "000000"}
colors = {"DCDCDC", "000000"}
else
else
local all_colors = mw.loadData(data_module)
local all_colors = mw.loadData(data_module)
colors = all_colors[team]
colors = all_colors[team]
if ( colors and type(colors) == 'string' ) then
if (colors and type(colors) == 'string') then
colors = all_colors[colors]
colors = all_colors[colors]
end
end
end
end

return colors or unknown
return colors or unknown
end
end
Line 108: Line 95:
local function team_color(team, num, num2)
local function team_color(team, num, num2)
local colors = get_colors(team, nil)
local colors = get_colors(team, nil)

num = tonumber(num:match('[1-3]') or '0')
num = tonumber(num:match('[1-3]') or '0')
num2 = tonumber(num2:match('[1-3]') or '0')
num2 = tonumber(num2:match('[1-3]') or '0')
if ( num ) then
if (num) then
return colors[num] or colors[num2] or ''
return colors[num] or colors[num2] or ''
else
else
Line 120: Line 106:
local function team_style1(team, borderwidth, fontcolor)
local function team_style1(team, borderwidth, fontcolor)
local colors = get_colors(team, nil)
local colors = get_colors(team, nil)

local color = '#' .. (colors[3] or colors[2] or '')
local color = '#' .. (colors[3] or colors[2] or '')
if fontcolor and fontcolor == 'auto' then
if fontcolor and fontcolor == 'auto' then
-- compute the luminosity of the background
local lum = color2lum(colors[1] or '')
local lum = color2lum(colors[1] or '')
local wcontrast = (1 + 0.05) / (lum + 0.05)
-- compute the contrast with white and black
local wcontrast = (1 + 0.05)/(lum + 0.05)
local bcontrast = (lum + 0.05) / (0 + 0.05)
fontcolor = (bcontrast > wcontrast + 1.25) and '#000000' or '#FFFFFF'
local bcontrast = (lum + 0.05)/(0 + 0.05)
-- select the text color with the best contrast
if( bcontrast > wcontrast + 1.25 ) then
fontcolor = '#000000'
else
fontcolor = '#FFFFFF'
end
end
end
local style = 'background-color:#' .. (colors[1] or '') .. ';color:' .. (fontcolor or color) .. ';'
local style = 'background-color:#' .. (colors[1] or '') .. ' !important;color:' .. (fontcolor or color) .. ' !important;'
if ((1 + 0.05) / (color2lum(color) + 0.05) < 1.25) then
-- remove the border if it's nearly white
if ((1 + 0.05)/(color2lum(color) + 0.05) < 1.25) then
borderwidth = '0'
borderwidth = '0'
end
end
Line 144: Line 121:
style = style .. bordercss(color, borderwidth)
style = style .. bordercss(color, borderwidth)
end
end

return style
return style
end
end
Line 150: Line 126:
local function team_style2(team, borderwidth, fontcolor)
local function team_style2(team, borderwidth, fontcolor)
local colors = get_colors(team, nil)
local colors = get_colors(team, nil)

local color = '#' .. (colors[1] or '')
local color = '#' .. (colors[1] or '')
if fontcolor and fontcolor == 'auto' then
if fontcolor and fontcolor == 'auto' then
-- compute the luminosity of the background
local lum = color2lum(colors[3] or colors[2] or '')
local lum = color2lum(colors[3] or colors[2] or '')
local wcontrast = (1 + 0.05) / (lum + 0.05)
-- compute the contrast with white and black
local wcontrast = (1 + 0.05)/(lum + 0.05)
local bcontrast = (lum + 0.05) / (0 + 0.05)
fontcolor = (bcontrast > wcontrast + 1.25) and '#000000' or '#FFFFFF'
local bcontrast = (lum + 0.05)/(0 + 0.05)
-- select the text color with the best contrast
if( bcontrast > wcontrast + 1.25 ) then
fontcolor = '#000000'
else
fontcolor = '#FFFFFF'
end
end
end
local style = 'background-color:#' .. (colors[3] or colors[2] or '') .. ';color:' .. (fontcolor or color) .. ';'
local style = 'background-color:#' .. (colors[3] or colors[2] or '') .. ' !important;color:' .. (fontcolor or color) .. ' !important;'
if ((1 + 0.05) / (color2lum(color) + 0.05) < 1.25) then
-- remove the border if it's nearly white
if ((1 + 0.05)/(color2lum(color) + 0.05) < 1.25) then
borderwidth = '0'
borderwidth = '0'
end
end
Line 174: Line 141:
style = style .. bordercss(color, borderwidth)
style = style .. bordercss(color, borderwidth)
end
end

return style
return style
end
end
Line 180: Line 146:
local function team_header1(team, borderwidth)
local function team_header1(team, borderwidth)
local colors = get_colors(team, nil)
local colors = get_colors(team, nil)
-- set the default background
local background = (colors[1] or 'FFFFFF'):upper()
local background = (colors[1] or 'FFFFFF'):upper()
if ((1 + 0.05) / (color2lum(background) + 0.05) < 1.25) then
-- set background to white if it's nearly white
if ((1 + 0.05)/(color2lum(background) + 0.05) < 1.25) then
background = 'FFFFFF'
background = 'FFFFFF'
end
end
-- now pick a font color
local fontcolor = '000000'
local fontcolor = '000000'
-- compute the luminosity of the background
local lum = color2lum(background)
local lum = color2lum(background)
local wcontrast = (1 + 0.05) / (lum + 0.05)
-- compute the contrast with white and black
local wcontrast = (1 + 0.05)/(lum + 0.05)
local bcontrast = (lum + 0.05) / (0 + 0.05)
local bcontrast = (lum + 0.05)/(0 + 0.05)
if (bcontrast > wcontrast + 1.25) then
-- select the text color with the best contrast
if( bcontrast > wcontrast + 1.25 ) then
fontcolor = '000000'
fontcolor = '000000'
else
else
fontcolor = 'FFFFFF'
fontcolor = 'FFFFFF'
end
end

local style
local style
if( background == 'FFFFFF' ) then
if (background == 'FFFFFF') then
style = 'background-color:none;color:#' .. fontcolor .. ';'
style = 'background-color:none !important;color:#' .. fontcolor .. ' !important;'
else
else
style = 'background-color:#' .. background .. ';color:#' .. fontcolor .. ';'
style = 'background-color:#' .. background .. ' !important;color:#' .. fontcolor .. ' !important;'
end
end

if borderwidth then
if borderwidth then
borderwidth = tonumber(borderwidth or '2') or 0
borderwidth = tonumber(borderwidth or '2') or 0
local bordercolor = (colors[3] or colors[2] or 'FFFFFF'):upper()
local bordercolor = (colors[3] or colors[2] or 'FFFFFF'):upper()
if (borderwidth > 0 and bordercolor ~= 'FFFFFF') then
if (borderwidth > 0 and bordercolor ~= 'FFFFFF' and (1 + 0.05) / (color2lum(bordercolor) + 0.05) >= 1.25) then
style = style .. bordercss('#' .. bordercolor, borderwidth)
-- do not add a border if it's nearly white
if ((1 + 0.05)/(color2lum(bordercolor) + 0.05) >= 1.25) then
style = style .. bordercss('#' .. bordercolor, borderwidth)
end
end
end
end
end
Line 222: Line 177:
local function team_header2(team)
local function team_header2(team)
local colors = get_colors(team, nil)
local colors = get_colors(team, nil)
-- set the default background
local background = (colors[3] or colors[2] or 'FFFFFF'):upper()
local background = (colors[3] or colors[2] or 'FFFFFF'):upper()
if ((1 + 0.05) / (color2lum(background) + 0.05) < 1.25) then
-- set background to white if it's nearly white
if ((1 + 0.05)/(color2lum(background) + 0.05) < 1.25) then
background = 'FFFFFF'
background = 'FFFFFF'
end
end
-- if the background is white, then use the primary background instead
if (background == 'FFFFFF') then
if( background == 'FFFFFF' ) then
background = (colors[1] or 'FFFFFF'):upper()
background = (colors[1] or 'FFFFFF'):upper()
end
end
-- now pick a font color
local fontcolor = '000000'
local fontcolor = '000000'
-- compute the luminosity of the background
local lum = color2lum(background)
local lum = color2lum(background)
local wcontrast = (1 + 0.05) / (lum + 0.05)
-- compute the contrast with white and black
local wcontrast = (1 + 0.05)/(lum + 0.05)
local bcontrast = (lum + 0.05) / (0 + 0.05)
local bcontrast = (lum + 0.05)/(0 + 0.05)
if (bcontrast > wcontrast + 1.25) then
-- select the text color with the best contrast
if( bcontrast > wcontrast + 1.25 ) then
fontcolor = '000000'
fontcolor = '000000'
else
else
fontcolor = 'FFFFFF'
fontcolor = 'FFFFFF'
end
end
if( background == 'FFFFFF' ) then
if (background == 'FFFFFF') then
return 'background-color:none;color:#' .. fontcolor .. ';'
return 'background-color:none !important;color:#' .. fontcolor .. ' !important;'
else
else
return 'background-color:#' .. background .. ';color:#' .. fontcolor .. ';'
return 'background-color:#' .. background .. ' !important;color:#' .. fontcolor .. ' !important;'
end
end
end
end
Line 255: Line 203:
local colors = get_colors(team, nil)
local colors = get_colors(team, nil)
local borderwidth = tonumber(args['border']) or 0
local borderwidth = tonumber(args['border']) or 0
-- set the default background
local background = (ctype == 'p') and
local background = (ctype == 'p') and
(colors[1] or 'FFFFFF'):upper() or
(colors[1] or 'FFFFFF'):upper() or
(colors[3] or colors[2] or 'FFFFFF'):upper()
(colors[3] or colors[2] or 'FFFFFF'):upper()
-- now pick a font color
local fontcolor = ''
local fontcolor = ''
-- compute the luminosity of the background
local lum = color2lum(background)
local lum = color2lum(background)
local wcontrast = (1 + 0.05) / (lum + 0.05)
-- compute the contrast with white and black
local wcontrast = (1 + 0.05)/(lum + 0.05)
local bcontrast = (lum + 0.05) / (0 + 0.05)
local bcontrast = (lum + 0.05)/(0 + 0.05)
if (bcontrast > wcontrast + 1.25) then
-- select the text color with the best contrast
if( bcontrast > wcontrast + 1.25 ) then
fontcolor = '#000000'
fontcolor = '#000000'
else
else
fontcolor = '#FFFFFF'
fontcolor = '#FFFFFF'
end
end
local s = 'background-color:#' .. background .. ';color:' .. (args['color'] or fontcolor) .. ';'
local s = 'background-color:#' .. background .. ' !important;color:' .. (args['color'] or fontcolor) .. ' !important;'
if borderwidth > 0 then
if borderwidth > 0 then
local bc = (ctype == 'p') and
local bc = (ctype == 'p') and
(colors[3] or colors[2] or '') or (colors[1] or '')
(colors[3] or colors[2] or '') or (colors[1] or '')
if bc ~= 'FFFFFF' then
if bc ~= 'FFFFFF' then
s = s .. bordercss('#' .. bc, borderwidth)
s = s .. bordercss('#' .. bc, borderwidth)
end
end
end
end

local res = '|-\n'
local res = '|-\n'
for i=1,50 do
for i = 1, 50 do
if( args[i] ~= nil ) then
if (args[i] ~= nil) then
local cstyle = 'scope="col" style="' .. s .. '"'
local cstyle = 'scope="col" style="' .. s .. '"'
if args['col' .. i .. 'span'] ~= nil then
if args['col' .. i .. 'span'] ~= nil then
cstyle = cstyle .. ' colspan=' .. args['col' .. i .. 'span']
cstyle = cstyle .. ' colspan=' .. args['col' .. i .. 'span']
end
end
if args['class' .. i ] ~= nil then
if args['class' .. i] ~= nil then
cstyle = cstyle .. ' class="' .. args['class' .. i] .. '"'
cstyle = cstyle .. ' class="' .. args['class' .. i] .. '"'
end
end
Line 297: Line 239:
end
end
return res .. '<span class="error">Error!</span>\n|-\n'
return res .. '<span class="error">Error!</span>\n|-\n'

end
end


local function team_stripe1(team, borderwidth)
local function team_stripe1(team, borderwidth)
local colors = get_colors(team, nil)
local colors = get_colors(team, nil)

-- set the default scheme
local background = colors[1] or ''
local background = colors[1] or ''
local fontcolor = colors[2] or ''
local fontcolor = colors[2] or ''
local bordercolor = (colors[3] or colors[2] or ''):upper()
local bordercolor = (colors[3] or colors[2] or ''):upper()
borderwidth = tonumber(borderwidth or '3') or 0
borderwidth = tonumber(borderwidth or '3') or 0

-- if there is no tertiary color, then pick a font color
if (colors[3] == nil) then
if (colors[3] == nil) then
-- compute the luminosity of the background
local lum = color2lum(colors[1])
local lum = color2lum(colors[1])
local wcontrast = (1 + 0.05) / (lum + 0.05)
-- compute the contrast with white and black
local wcontrast = (1 + 0.05)/(lum + 0.05)
local bcontrast = (lum + 0.05) / (0 + 0.05)
fontcolor = (bcontrast > wcontrast + 1.25) and '000000' or 'FFFFFF'
local bcontrast = (lum + 0.05)/(0 + 0.05)
-- select the text color with the best contrast
if( bcontrast > wcontrast + 1.25 ) then
fontcolor = '000000'
else
fontcolor = 'FFFFFF'
end
end
end
local style = 'background-color:#' .. background .. ' !important;color:#' .. fontcolor .. ' !important;'

-- finally build the style string
local style = ''
if (borderwidth > 0) then
if (borderwidth > 0) then
local bordercontrast = (1 + 0.05) / (color2lum(bordercolor) + 0.05)
-- use the primary as the border if the border is white or close to white
local bordercontrast = (1 + 0.05)/(color2lum(bordercolor) + 0.05)
if (bordercontrast < 1.25) then
if (bordercontrast < 1.25) then
bordercolor = background
bordercolor = background
local fontcontrast = (1 + 0.05)/(color2lum(colors[2] or 'FFFFFF') + 0.05)
local fontcontrast = (1 + 0.05) / (color2lum(colors[2] or 'FFFFFF') + 0.05)
if (fontcontrast < 1.25) then
if (fontcontrast < 1.25) then
fontcolor = colors[2] or 'FFFFFF'
fontcolor = colors[2] or 'FFFFFF'
end
end
end
end
style = style .. ' border:' .. borderwidth .. 'px solid #' .. bordercolor .. ';'
style = style .. 'border:' .. borderwidth .. 'px solid #' .. bordercolor .. ' !important;'
style = style .. ' border-left: none; border-right: none;'
style = style .. 'border-left:none;border-right:none;'
style = style .. ' box-shadow: inset 0 2px 0 #FEFEFE, inset 0 -2px 0 #FEFEFE;'
style = style .. 'box-shadow:inset 0 2px 0 #FEFEFE, inset 0 -2px 0 #FEFEFE;'
end
end
style = 'background-color:#' .. background .. ';color:#' .. fontcolor .. ';' .. style

return style
return style
end
end


local function team_boxes(frame, team, order, sep)
local function team_boxes(frame, team, order, sep)
local function colorbox( h )
local function colorbox(h)
local r = mw.html.create('')
local r = mw.html.create('')
r:tag('span')
r:tag('span')
:addClass('legend-color')
:addClass('legend-color')
:addClass('mw-no-invert')
:css('background-color', '#' .. (h or ''))
:css('background-color', '#' .. (h or '') .. ' !important')
:wikitext('&nbsp;')
:css('display', 'inline-block')
:wikitext(' ')
return tostring(r)
return tostring(r)
end
end

local colors = get_colors(team, 'unknown')
local colors = get_colors(team, 'unknown')

if type(colors) ~= 'table' then
if type(colors) ~= 'table' then
return ''
return ''
end
end

local colorboxes = {}
local colorboxes = {}
local colororder = {'1','2','3','4','5'}
local colororder = {'1', '2', '3', '4', '5'}
local namecheck = 0
local namecheck = 0
if order == '' then
if order == '' then
Line 371: Line 295:
colororder = mw.text.split(order, '')
colororder = mw.text.split(order, '')
end
end
for k,v in pairs(colororder) do
for k, v in pairs(colororder) do
local i = tonumber(v) or 0
local i = tonumber(v) or 0
if( namecheck == 0 or colors['name' .. i]) then
if (namecheck == 0 or colors['name' .. i]) then
if colors[i] then
if colors[i] then
table.insert(colorboxes,colorbox(colors[i]))
table.insert(colorboxes, colorbox(colors[i]))
end
end
end
end
end
end

if (#colorboxes > 0) then
if (#colorboxes > 0) then
return frame:extensionTag{ name = 'templatestyles', args = { src = 'Legend/styles.css'} } .. table.concat(colorboxes, sep)
return frame:extensionTag{ name = 'templatestyles', args = { src = 'Legend/styles.css' } } .. table.concat(colorboxes, sep)
end
end

return ''
return ''
end
end


local function team_list(frame, team, num1, num2, num3, num4, num5, sep)
local function team_list(frame, team, num1, num2, num3, num4, num5, sep)
local function colorbox( h )
local function colorbox(h)
local r = mw.html.create('')
local r = mw.html.create('')
r:tag('span')
r:tag('span')
:addClass('legend-color')
:addClass('legend-color')
:addClass('mw-no-invert')
:css('background-color', '#' .. (h or ''))
:css('background-color', '#' .. (h or '') .. ' !important')
:wikitext('&nbsp;')
:css('display', 'inline-block')
:wikitext(' ')
return tostring(r)
return tostring(r)
end
end

local colors = get_colors(team, 'unknown')
local colors = get_colors(team, 'unknown')

if type(colors) ~= 'table' then
if type(colors) ~= 'table' then
return ''
return ''
end
end

local nums = {
local nums = {
tonumber(num1:match('[1-5]') or '0') or 0,
tonumber(num1:match('[1-5]') or '0') or 0,
Line 408: Line 329:
tonumber(num3:match('[1-5]') or '0') or 0,
tonumber(num3:match('[1-5]') or '0') or 0,
tonumber(num4:match('[1-5]') or '0') or 0,
tonumber(num4:match('[1-5]') or '0') or 0,
tonumber(num5:match('[1-5]') or '0') or 0}
tonumber(num5:match('[1-5]') or '0') or 0
}

local colorboxes = {}
local colorboxes = {}
local colornames = {}
local colornames = {}
local colororder = {'1','2','3','4','5'}
local colororder = {'1', '2', '3', '4', '5'}
local order = colors['order'] or ''
local order = colors['order'] or ''
if(order ~= '') then
if (order ~= '') then
colororder = mw.text.split(order, '')
colororder = mw.text.split(order, '')
end
end
for k,v in pairs(colororder) do
for k, v in pairs(colororder) do
local i = tonumber(v) or 0
local i = tonumber(v) or 0
if ( nums[i] > 0 ) then
if (nums[i] > 0) then
if( colors['name' .. nums[i]]) then
if (colors['name' .. nums[i]]) then
table.insert(colornames,colors['name' .. nums[i]])
table.insert(colornames, colors['name' .. nums[i]])
table.insert(colorboxes,colorbox(colors[nums[i]] or ''))
table.insert(colorboxes, colorbox(colors[nums[i]] or ''))
end
end
end
end
end
end

local res = ''
local res = ''
if (#colornames > 0) then
if (#colornames > 0) then
colornames[1] = ucfirst(colornames[1])
colornames[1] = ucfirst(colornames[1])
end
end
res = mw.text.listToText(
res = mw.text.listToText(
colornames,
colornames,
',&nbsp;',
', ',
#colornames == 2 and '&nbsp;and&nbsp;' or ',&nbsp;and&nbsp;'
#colornames == 2 and ' and ' or ', and '
)
)

if (colors['cite']) then
if (colors['cite']) then
res = res .. frame:preprocess('<ref>' .. colors['cite'] .. '</ref>')
res = res .. frame:preprocess('<ref>' .. colors['cite'] .. '</ref>')
Line 447: Line 365:
res = res .. '[' .. colors['ref2'] .. ']'
res = res .. '[' .. colors['ref2'] .. ']'
end
end

if (#colornames > 0) then
if (#colornames > 0) then
res = res .. sep
res = res .. sep
end
end

if (#colorboxes > 0) then
if (#colorboxes > 0) then
res = res .. frame:extensionTag{ name = 'templatestyles', args = { src = 'Legend/styles.css'} }
res = res .. frame:extensionTag{ name = 'templatestyles', args = { src = 'Legend/styles.css' } }
res = res .. table.concat(colorboxes, '&nbsp;')
res = res .. table.concat(colorboxes, ' ')
end
end

return res
return res
end
end
Line 522: Line 437:
local args = (frame.args[1] ~= nil) and frame.args or frame:getParent().args
local args = (frame.args[1] ~= nil) and frame.args or frame:getParent().args
return team_boxes(frame, remove_sport(args[1] or ''),
return team_boxes(frame, remove_sport(args[1] or ''),
args['order'] or '', args['sep'] or '&nbsp;')
args['order'] or '', args['sep'] or ' ')
end
end


Line 537: Line 452:


function p.check_data()
function p.check_data()
-- In a sandbox, preview {{#invoke:college color|check_data}}
local results = {'Problems in [[Module:College color/data]]:'}
local results = {'Problems in [[Module:College color/data]]:'}
local function problems(msg)
local function problems(msg)

Revision as of 17:11, 26 March 2025

--
-- This module implements {{CollegePrimaryHex}}, {{CollegePrimaryStyle}},
-- {{CollegeSecondaryHex}}, {{CollegeSecondaryStyle}}, {{CollegeSecondaryColorLink}}, and {{NCAA color}}
--
local p = {}

local data_module = "Module:College color/data"

local function stripwhitespace(text)
	return text:match("^%s*(.-)%s*$")
end
local function ucfirst(s)
	local first = s:sub(1, 1)
	local others = s:sub(2, -1)
	return first:upper() .. others
end
local function bordercss(c, w)
	local s = 'inset ' .. w .. 'px ' .. w .. 'px 0 ' .. c 
		.. ', inset -' .. w .. 'px -' .. w .. 'px 0 ' .. c
	return 'box-shadow: ' .. s .. ';'
end
local function sRGB(v)
	if (v <= 0.03928) then
		v = v / 12.92
	else
		v = math.pow((v + 0.055) / 1.055, 2.4)
	end
	return v
end
local function color2lum(origc)
	local c = stripwhitespace(origc or ''):lower()
	c = mw.ustring.match(c, '^[#]*([a-f0-9]*)$')
	local cs = mw.text.split(c or '', '')
	if (#cs == 6) then
		local R = sRGB((16 * tonumber('0x' .. cs[1]) + tonumber('0x' .. cs[2])) / 255)
		local G = sRGB((16 * tonumber('0x' .. cs[3]) + tonumber('0x' .. cs[4])) / 255)
		local B = sRGB((16 * tonumber('0x' .. cs[5]) + tonumber('0x' .. cs[6])) / 255)
		return 0.2126 * R + 0.7152 * G + 0.0722 * B
	elseif (#cs == 3) then
		local R = sRGB((16 * tonumber('0x' .. cs[1]) + tonumber('0x' .. cs[1])) / 255)
		local G = sRGB((16 * tonumber('0x' .. cs[2]) + tonumber('0x' .. cs[2])) / 255)
		local B = sRGB((16 * tonumber('0x' .. cs[3]) + tonumber('0x' .. cs[3])) / 255)
		return 0.2126 * R + 0.7152 * G + 0.0722 * B
	end
	error('Invalid hex color ' .. origc, 2)
end

local function remove_sport(team)
	team = mw.ustring.gsub(team, "%s*<[Bb][Rr][^<>]*>%s*", ' ')
	team = mw.ustring.gsub(team, " [Tt]eam$", '')
	team = mw.ustring.gsub(team, " [Bb]asketball$", '')
	team = mw.ustring.gsub(team, " [Bb]aseball$", '')
	team = mw.ustring.gsub(team, " [Cc]ross [Cc]ountry$", '')
	team = mw.ustring.gsub(team, " [Ff]ield [Hh]ockey$", '')
	team = mw.ustring.gsub(team, " [Ff]ootball$", '')
	team = mw.ustring.gsub(team, " [Gg]olf$", '')
	team = mw.ustring.gsub(team, " [Gg]ymnastics$", '')
	team = mw.ustring.gsub(team, " [Ii]ce [Hh]ockey$", '')
	team = mw.ustring.gsub(team, " [Ll]acrosse$", '')
	team = mw.ustring.gsub(team, " [Rr]owing$", '')
	team = mw.ustring.gsub(team, " [Ss]ki$", '')
	team = mw.ustring.gsub(team, " [Ss]occer$", '')
	team = mw.ustring.gsub(team, " [Ss]oftball$", '')
	team = mw.ustring.gsub(team, " [Ss]wim$", '')
	team = mw.ustring.gsub(team, " [Tt]ennis$", '')
	team = mw.ustring.gsub(team, " [Tt]rack [Aa]nd [Ff]ield$", '')
	team = mw.ustring.gsub(team, " [Vv]olleyball$", '')
	team = mw.ustring.gsub(team, " [Ww]restling$", '')
	team = mw.ustring.gsub(team, " [Ww]omen's$", '')
	team = mw.ustring.gsub(team, " [Mm]en's$", '')
	return team
end

local function get_colors(team, unknown)
	team = stripwhitespace(team or '')
	unknown = unknown or {"DCDCDC", "000000"}
	local use_default = {
		[""] = 1,
		["retired"] = 1,
		["free agent"] = 1,
	}
	local colors = nil
	if (team and use_default[team:lower()]) then
		colors = {"DCDCDC", "000000"}
	else
		local all_colors = mw.loadData(data_module)
		colors = all_colors[team]
		if (colors and type(colors) == 'string') then
			colors = all_colors[colors]
		end
	end
	return colors or unknown
end

local function team_color(team, num, num2)
	local colors = get_colors(team, nil)
	num = tonumber(num:match('[1-3]') or '0')
	num2 = tonumber(num2:match('[1-3]') or '0')
	if (num) then
		return colors[num] or colors[num2] or ''
	else
		return ''
	end
end

local function team_style1(team, borderwidth, fontcolor)
	local colors = get_colors(team, nil)
	local color = '#' .. (colors[3] or colors[2] or '')
	if fontcolor and fontcolor == 'auto' then
		local lum = color2lum(colors[1] or '')
		local wcontrast = (1 + 0.05) / (lum + 0.05)
		local bcontrast = (lum + 0.05) / (0 + 0.05)
		fontcolor = (bcontrast > wcontrast + 1.25) and '#000000' or '#FFFFFF'
	end
	local style = 'background-color:#' .. (colors[1] or '') .. ' !important;color:' .. (fontcolor or color) .. ' !important;'
	if ((1 + 0.05) / (color2lum(color) + 0.05) < 1.25) then
		borderwidth = '0'
	end
	borderwidth = tonumber(borderwidth or '2') or 0
	if (borderwidth > 0 and color ~= '#FFFFFF') then
		style = style .. bordercss(color, borderwidth)
	end
	return style
end

local function team_style2(team, borderwidth, fontcolor)
	local colors = get_colors(team, nil)
	local color = '#' .. (colors[1] or '')
	if fontcolor and fontcolor == 'auto' then
		local lum = color2lum(colors[3] or colors[2] or '')
		local wcontrast = (1 + 0.05) / (lum + 0.05)
		local bcontrast = (lum + 0.05) / (0 + 0.05)
		fontcolor = (bcontrast > wcontrast + 1.25) and '#000000' or '#FFFFFF'
	end
	local style = 'background-color:#' .. (colors[3] or colors[2] or '') .. ' !important;color:' .. (fontcolor or color) .. ' !important;'
	if ((1 + 0.05) / (color2lum(color) + 0.05) < 1.25) then
		borderwidth = '0'
	end
	borderwidth = tonumber(borderwidth or '2') or 0
	if (borderwidth > 0 and color ~= '#FFFFFF') then
		style = style .. bordercss(color, borderwidth)
	end
	return style
end

local function team_header1(team, borderwidth)
	local colors = get_colors(team, nil)
	local background = (colors[1] or 'FFFFFF'):upper()
	if ((1 + 0.05) / (color2lum(background) + 0.05) < 1.25) then
		background = 'FFFFFF'
	end
	local fontcolor = '000000'
	local lum = color2lum(background)
	local wcontrast = (1 + 0.05) / (lum + 0.05)
	local bcontrast = (lum + 0.05) / (0 + 0.05)
	if (bcontrast > wcontrast + 1.25) then
		fontcolor = '000000'
	else
		fontcolor = 'FFFFFF'
	end
	local style
	if (background == 'FFFFFF') then
		style = 'background-color:none !important;color:#' .. fontcolor .. ' !important;'
	else
		style = 'background-color:#' .. background .. ' !important;color:#' .. fontcolor .. ' !important;'
	end
	if borderwidth then
		borderwidth = tonumber(borderwidth or '2') or 0
		local bordercolor = (colors[3] or colors[2] or 'FFFFFF'):upper()
		if (borderwidth > 0 and bordercolor ~= 'FFFFFF' and (1 + 0.05) / (color2lum(bordercolor) + 0.05) >= 1.25) then
			style = style .. bordercss('#' .. bordercolor, borderwidth)
		end
	end
	return style
end

local function team_header2(team)
	local colors = get_colors(team, nil)
	local background = (colors[3] or colors[2] or 'FFFFFF'):upper()
	if ((1 + 0.05) / (color2lum(background) + 0.05) < 1.25) then
		background = 'FFFFFF'
	end
	if (background == 'FFFFFF') then
		background = (colors[1] or 'FFFFFF'):upper()
	end
	local fontcolor = '000000'
	local lum = color2lum(background)
	local wcontrast = (1 + 0.05) / (lum + 0.05)
	local bcontrast = (lum + 0.05) / (0 + 0.05)
	if (bcontrast > wcontrast + 1.25) then
		fontcolor = '000000'
	else
		fontcolor = 'FFFFFF'
	end
	if (background == 'FFFFFF') then
		return 'background-color:none !important;color:#' .. fontcolor .. ' !important;'
	else
		return 'background-color:#' .. background .. ' !important;color:#' .. fontcolor .. ' !important;'
	end
end

local function team_table_head(args, team, ctype)
	local colors = get_colors(team, nil)
	local borderwidth = tonumber(args['border']) or 0
	local background = (ctype == 'p') and
		(colors[1] or 'FFFFFF'):upper() or
		(colors[3] or colors[2] or 'FFFFFF'):upper()
	local fontcolor = ''
	local lum = color2lum(background)
	local wcontrast = (1 + 0.05) / (lum + 0.05)
	local bcontrast = (lum + 0.05) / (0 + 0.05)
	if (bcontrast > wcontrast + 1.25) then
		fontcolor = '#000000'
	else
		fontcolor = '#FFFFFF'
	end
	local s = 'background-color:#' .. background .. ' !important;color:' .. (args['color'] or fontcolor) .. ' !important;'
	if borderwidth > 0 then
		local bc = (ctype == 'p') and 
			(colors[3] or colors[2] or '') or (colors[1] or '')
		if bc ~= 'FFFFFF' then
			s = s .. bordercss('#' .. bc, borderwidth)
		end
	end
	local res = '|-\n'
	for i = 1, 50 do
		if (args[i] ~= nil) then
			local cstyle = 'scope="col" style="' .. s .. '"'
			if args['col' .. i .. 'span'] ~= nil then
				cstyle = cstyle .. ' colspan=' .. args['col' .. i .. 'span']
			end
			if args['class' .. i] ~= nil then
				cstyle = cstyle .. ' class="' .. args['class' .. i] .. '"'
			end
			res = res .. '! ' .. cstyle .. ' |' .. args[i] .. '\n'
		else
			return res .. '|-\n'
		end
	end
	return res .. '<span class="error">Error!</span>\n|-\n'
end

local function team_stripe1(team, borderwidth)
	local colors = get_colors(team, nil)
	local background = colors[1] or ''
	local fontcolor = colors[2] or ''
	local bordercolor = (colors[3] or colors[2] or ''):upper()
	borderwidth = tonumber(borderwidth or '3') or 0
	if (colors[3] == nil) then
		local lum = color2lum(colors[1])
		local wcontrast = (1 + 0.05) / (lum + 0.05)
		local bcontrast = (lum + 0.05) / (0 + 0.05)
		fontcolor = (bcontrast > wcontrast + 1.25) and '000000' or 'FFFFFF'
	end
	local style = 'background-color:#' .. background .. ' !important;color:#' .. fontcolor .. ' !important;'
	if (borderwidth > 0) then
		local bordercontrast = (1 + 0.05) / (color2lum(bordercolor) + 0.05)
		if (bordercontrast < 1.25) then
			bordercolor = background
			local fontcontrast = (1 + 0.05) / (color2lum(colors[2] or 'FFFFFF') + 0.05)
			if (fontcontrast < 1.25) then
				fontcolor = colors[2] or 'FFFFFF'
			end
		end
		style = style .. 'border:' .. borderwidth .. 'px solid #' .. bordercolor .. ' !important;'
		style = style .. 'border-left:none;border-right:none;'
		style = style .. 'box-shadow:inset 0 2px 0 #FEFEFE, inset 0 -2px 0 #FEFEFE;'
	end
	return style
end

local function team_boxes(frame, team, order, sep)
	local function colorbox(h)
		local r = mw.html.create('')
		r:tag('span')
			:addClass('legend-color')
			:addClass('mw-no-invert')
			:css('background-color', '#' .. (h or '') .. ' !important')
			:css('display', 'inline-block')
			:wikitext(' ')
		return tostring(r)
	end
	local colors = get_colors(team, 'unknown')
	if type(colors) ~= 'table' then
		return ''
	end
	local colorboxes = {}
	local colororder = {'1', '2', '3', '4', '5'}
	local namecheck = 0
	if order == '' then
		order = colors['order'] or ''
		namecheck = 1
	end
	if order ~= '' then
		colororder = mw.text.split(order, '')
	end
	for k, v in pairs(colororder) do
		local i = tonumber(v) or 0
		if (namecheck == 0 or colors['name' .. i]) then
			if colors[i] then
				table.insert(colorboxes, colorbox(colors[i]))
			end
		end
	end
	if (#colorboxes > 0) then
		return frame:extensionTag{ name = 'templatestyles', args = { src = 'Legend/styles.css' } } .. table.concat(colorboxes, sep)
	end
	return ''
end

local function team_list(frame, team, num1, num2, num3, num4, num5, sep)
	local function colorbox(h)
		local r = mw.html.create('')
		r:tag('span')
			:addClass('legend-color')
			:addClass('mw-no-invert')
			:css('background-color', '#' .. (h or '') .. ' !important')
			:css('display', 'inline-block')
			:wikitext(' ')
		return tostring(r)
	end
	local colors = get_colors(team, 'unknown')
	if type(colors) ~= 'table' then
		return ''
	end
	local nums = {
		tonumber(num1:match('[1-5]') or '0') or 0,
		tonumber(num2:match('[1-5]') or '0') or 0,
		tonumber(num3:match('[1-5]') or '0') or 0,
		tonumber(num4:match('[1-5]') or '0') or 0,
		tonumber(num5:match('[1-5]') or '0') or 0
	}
	local colorboxes = {}
	local colornames = {}
	local colororder = {'1', '2', '3', '4', '5'}
	local order = colors['order'] or ''
	if (order ~= '') then
		colororder = mw.text.split(order, '')
	end
	for k, v in pairs(colororder) do
		local i = tonumber(v) or 0
		if (nums[i] > 0) then
			if (colors['name' .. nums[i]]) then
				table.insert(colornames, colors['name' .. nums[i]])
				table.insert(colorboxes, colorbox(colors[nums[i]] or ''))
			end
		end
	end
	local res = ''
	if (#colornames > 0) then
		colornames[1] = ucfirst(colornames[1])
	end
	res = mw.text.listToText(
		colornames,
		', ',
		#colornames == 2 and ' and ' or ', and '
	)
	if (colors['cite']) then
		res = res .. frame:preprocess('<ref>' .. colors['cite'] .. '</ref>')
	end
	if (colors['ref']) then
		res = res .. '[' .. colors['ref'] .. ']'
	end
	if (colors['ref2']) then
		res = res .. '[' .. colors['ref2'] .. ']'
	end
	if (#colornames > 0) then
		res = res .. sep
	end
	if (#colorboxes > 0) then
		res = res .. frame:extensionTag{ name = 'templatestyles', args = { src = 'Legend/styles.css' } }
		res = res .. table.concat(colorboxes, ' ')
	end
	return res
end

local function team_check(team, unknown)
	local colors = get_colors(team, unknown)
	if type(colors) == 'table' then
		return 'known'
	else
		return unknown
	end
end

function p.color(frame)
	local args = (frame.args[1] ~= nil) and frame.args or frame:getParent().args
	return team_color(remove_sport(args[1] or ''), args[2] or '', args[3] or '')
end

function p.color1(frame)
	local args = (frame.args[1] ~= nil) and frame.args or frame:getParent().args
	return team_color(remove_sport(args[1] or ''), '1', '')
end

function p.color32(frame)
	local args = (frame.args[1] ~= nil) and frame.args or frame:getParent().args
	return team_color(remove_sport(args[1] or ''), '3', '2')
end

function p.style1(frame)
	local args = (frame.args[1] ~= nil) and frame.args or frame:getParent().args
	return team_style1(remove_sport(args[1] or ''), args['border'], args['color'])
end

function p.style2(frame)
	local args = (frame.args[1] ~= nil) and frame.args or frame:getParent().args
	return team_style2(remove_sport(args[1] or ''), args['border'], args['color'])
end

function p.header1(frame)
	local args = (frame.args[1] ~= nil) and frame.args or frame:getParent().args
	return team_header1(remove_sport(args[1] or ''), args['border'])
end

function p.header2(frame)
	local args = (frame.args[1] ~= nil) and frame.args or frame:getParent().args
	return team_header2(remove_sport(args[1] or ''))
end

function p.tablehead1(frame)
	local args = (frame.args[1] ~= nil) and frame.args or frame:getParent().args
	return team_table_head(args, remove_sport(args['team'] or ''), 'p')
end

function p.tablehead2(frame)
	local args = (frame.args[1] ~= nil) and frame.args or frame:getParent().args
	return team_table_head(args, remove_sport(args['team'] or ''), 's')
end

function p.stripe1(frame)
	local args = (frame.args[1] ~= nil) and frame.args or frame:getParent().args
	return team_stripe1(remove_sport(args[1] or ''), args['border'])
end

function p.boxes(frame)
	local args = (frame.args[1] ~= nil) and frame.args or frame:getParent().args
	return team_boxes(frame, remove_sport(args[1] or ''),
		args['order'] or '', args['sep'] or ' ')
end

function p.list(frame)
	local args = (frame.args[1] ~= nil) and frame.args or frame:getParent().args
	return team_list(frame, remove_sport(args[1] or ''),
		args[2] or '1', args[3] or '2', args[4] or '3', args[5] or '4', args[6] or '5', args['sep'] or '')
end

function p.check(frame)
	local args = (frame.args[1] ~= nil) and frame.args or frame:getParent().args
	return team_check(remove_sport(args[1] or ''), args[2] or '')
end

function p.check_data()
	local results = {'Problems in [[Module:College color/data]]:'}
	local function problems(msg)
		if msg then
			table.insert(results, msg)
		elseif results[2] then
			return table.concat(results, '\n*')
		else
			return 'No problems detected.'
		end
	end
	local data = require(data_module)
	local keys = {}
	for k, _ in pairs(data) do
		table.insert(keys, k)
	end
	table.sort(keys)
	for _, key in ipairs(keys) do
		local val = data[key]
		if not (type(key) == 'string' and (type(val) == 'table' or type(val) == 'string')) then
			problems('Invalid type for "' .. tostring(key) .. '"')
		end
		if type(val) == 'table' then
			if not (2 <= #val and #val <= 4) then
				problems('Invalid number of numbered parameters for "' .. tostring(key) .. '"')
			end
			for i, v in ipairs(val) do
				if not tostring(v):match('^%x%x%x%x%x%x$') then
					problems('Parameter [' .. i .. '] should be a 6-hex-digit color but is "' .. tostring(v) .. '" for "' .. tostring(key) .. '"')
				end
			end
			for k, v in pairs(val) do
				if type(k) == 'number' then
					if not (1 <= k and k <= 4) then
						problems('Invalid numbered parameter for "' .. tostring(key) .. '"')
					end
				elseif type(k) == 'string' then
					if not (
							k:match('^name[1-4]$') or
							k:match('^cite2?$') or
							k:match('^order$')
							) then
						problems('Unexpected key in table for "' .. tostring(key) .. '"')
					end
				else
					problems('Invalid key type in table for "' .. tostring(key) .. '"')
				end
			end
		elseif data[val] == nil then
			problems('Undefined alias for "' .. tostring(key) .. '"')
		elseif type(data[val]) ~= 'table' then
			problems('Alias is not a table for "' .. tostring(key) .. '"')
		end
	end
	return problems()
end

function p.testtable(frame)
	local contrasttable_mod = require("Module:College color/contrast")
	return contrasttable_mod._testtable(frame.args)
end

return p