Jump to content

Module:College color: Difference between revisions

From Wikipedia, the free encyclopedia
Content deleted Content added
yet another attempted dark mode fix
Tag: Reverted
No edit summary
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 20: Line 21:
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 69: Line 78:
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 80: Line 90:
["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 95: Line 108:
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 106: Line 120:
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 '')
-- compute the contrast with white and black
local wcontrast = (1 + 0.05) / (lum + 0.05)
local bcontrast = (lum + 0.05) / (0 + 0.05)
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'
-- 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 '') .. ' !important;color:' .. (fontcolor or color) .. ' !important;'
local style = 'background-color:#' .. (colors[1] or '') .. ';color:' .. (fontcolor or color) .. ';'
-- remove the border if it's nearly white
if ((1 + 0.05) / (color2lum(color) + 0.05) < 1.25) then
if ((1 + 0.05)/(color2lum(color) + 0.05) < 1.25) then
borderwidth = '0'
borderwidth = '0'
end
end
Line 121: Line 144:
style = style .. bordercss(color, borderwidth)
style = style .. bordercss(color, borderwidth)
end
end

return style
return style
end
end
Line 126: Line 150:
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 '')
-- compute the contrast with white and black
local wcontrast = (1 + 0.05) / (lum + 0.05)
local bcontrast = (lum + 0.05) / (0 + 0.05)
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'
-- 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 '') .. ' !important;color:' .. (fontcolor or color) .. ' !important;'
local style = 'background-color:#' .. (colors[3] or colors[2] or '') .. ';color:' .. (fontcolor or color) .. ';'
-- remove the border if it's nearly white
if ((1 + 0.05) / (color2lum(color) + 0.05) < 1.25) then
if ((1 + 0.05)/(color2lum(color) + 0.05) < 1.25) then
borderwidth = '0'
borderwidth = '0'
end
end
Line 141: Line 174:
style = style .. bordercss(color, borderwidth)
style = style .. bordercss(color, borderwidth)
end
end

return style
return style
end
end
Line 146: Line 180:
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()
-- set background to white if it's nearly white
if ((1 + 0.05) / (color2lum(background) + 0.05) < 1.25) then
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)
-- compute the contrast with white and black
local wcontrast = (1 + 0.05) / (lum + 0.05)
local bcontrast = (lum + 0.05) / (0 + 0.05)
local wcontrast = (1 + 0.05)/(lum + 0.05)
if (bcontrast > wcontrast + 1.25) then
local bcontrast = (lum + 0.05)/(0 + 0.05)
-- 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 !important;color:#' .. fontcolor .. ' !important;'
style = 'background-color:none;color:#' .. fontcolor .. ';'
else
else
style = 'background-color:#' .. background .. ' !important;color:#' .. fontcolor .. ' !important;'
style = 'background-color:#' .. background .. ';color:#' .. fontcolor .. ';'
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' and (1 + 0.05) / (color2lum(bordercolor) + 0.05) >= 1.25) then
if (borderwidth > 0 and bordercolor ~= 'FFFFFF') then
-- 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)
style = style .. bordercss('#' .. bordercolor, borderwidth)
end
end
end
end
end
Line 177: Line 222:
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()
-- set background to white if it's nearly white
if ((1 + 0.05) / (color2lum(background) + 0.05) < 1.25) then
if ((1 + 0.05)/(color2lum(background) + 0.05) < 1.25) then
background = 'FFFFFF'
background = 'FFFFFF'
end
end
if (background == 'FFFFFF') then
-- if the background is white, then use the primary background instead
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)
-- compute the contrast with white and black
local wcontrast = (1 + 0.05) / (lum + 0.05)
local bcontrast = (lum + 0.05) / (0 + 0.05)
local wcontrast = (1 + 0.05)/(lum + 0.05)
if (bcontrast > wcontrast + 1.25) then
local bcontrast = (lum + 0.05)/(0 + 0.05)
-- 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 !important;color:#' .. fontcolor .. ' !important;'
return 'background-color:none;color:#' .. fontcolor .. ';'
else
else
return 'background-color:#' .. background .. ' !important;color:#' .. fontcolor .. ' !important;'
return 'background-color:#' .. background .. ';color:#' .. fontcolor .. ';'
end
end
end
end
Line 203: Line 255:
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)
-- compute the contrast with white and black
local wcontrast = (1 + 0.05) / (lum + 0.05)
local bcontrast = (lum + 0.05) / (0 + 0.05)
local wcontrast = (1 + 0.05)/(lum + 0.05)
if (bcontrast > wcontrast + 1.25) then
local bcontrast = (lum + 0.05)/(0 + 0.05)
-- 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 .. ' !important;color:' .. (args['color'] or fontcolor) .. ' !important;'
local s = 'background-color:#' .. background .. ';color:' .. (args['color'] or fontcolor) .. ';'
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 239: Line 297:
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])
-- compute the contrast with white and black
local wcontrast = (1 + 0.05) / (lum + 0.05)
local bcontrast = (lum + 0.05) / (0 + 0.05)
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'
-- 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
-- use the primary as the border if the border is white or close to white
local bordercontrast = (1 + 0.05) / (color2lum(bordercolor) + 0.05)
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 .. ' !important;'
style = style .. ' border:' .. borderwidth .. 'px solid #' .. bordercolor .. ';'
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')
:css('background-color', '#' .. (h or ''))
:addClass('mw-no-invert')
:wikitext('&nbsp;')
:css('background-color', '#' .. (h or '') .. ' !important')
: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 295: Line 371:
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')
:css('background-color', '#' .. (h or ''))
:addClass('mw-no-invert')
:wikitext('&nbsp;')
:css('background-color', '#' .. (h or '') .. ' !important')
: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 329: Line 408:
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 ' and ' or ', and '
#colornames == 2 and '&nbsp;and&nbsp;' or ',&nbsp;and&nbsp;'
)
)

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 365: Line 447:
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, ' ')
res = res .. table.concat(colorboxes, '&nbsp;')
end
end

return res
return res
end
end
Line 437: Line 522:
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 ' ')
args['order'] or '', args['sep'] or '&nbsp;')
end
end


Line 452: Line 537:


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:13, 26 March 2025

--
-- This module implements {{CollegePrimaryHex}}, {{CollegePrimaryStyle}},
-- {{CollegePrimaryColorLink}}, {{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()

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

	-- split into rgb
	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

	-- failure
	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
		-- compute the luminosity of the background
		local lum = color2lum(colors[1] or '')
		-- compute the contrast with white and black
		local wcontrast = (1 + 0.05)/(lum + 0.05)
		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
	local style = 'background-color:#' .. (colors[1] or '') .. ';color:' .. (fontcolor or color) .. ';'
	-- remove the border if it's nearly white
	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
		-- compute the luminosity of the background
		local lum = color2lum(colors[3] or colors[2] or '')
		-- compute the contrast with white and black
		local wcontrast = (1 + 0.05)/(lum + 0.05)
		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
	local style = 'background-color:#' .. (colors[3] or colors[2] or '') .. ';color:' .. (fontcolor or color) .. ';'
	-- remove the border if it's nearly white
	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)
	-- set the default background
	local background = (colors[1] or 'FFFFFF'):upper()
	-- set background to white if it's nearly white
	if ((1 + 0.05)/(color2lum(background) + 0.05) < 1.25) then
		background = 'FFFFFF'
	end
	-- now pick a font color
	local fontcolor = '000000'
	-- compute the luminosity of the background
	local lum = color2lum(background)
	-- compute the contrast with white and black
	local wcontrast = (1 + 0.05)/(lum + 0.05)
	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

	local style
	if( background == 'FFFFFF' ) then
		style = 'background-color:none;color:#' .. fontcolor .. ';'
	else
		style = 'background-color:#' .. background .. ';color:#' .. fontcolor .. ';'
	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') then
			-- 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
	return style
end

local function team_header2(team)
	local colors = get_colors(team, nil)
	-- set the default background
	local background = (colors[3] or colors[2] or 'FFFFFF'):upper()
	-- set background to white if it's nearly white
	if ((1 + 0.05)/(color2lum(background) + 0.05) < 1.25) then
		background = 'FFFFFF'
	end
	-- if the background is white, then use the primary background instead
	if( background == 'FFFFFF' ) then
		background = (colors[1] or 'FFFFFF'):upper()
	end
	-- now pick a font color
	local fontcolor = '000000'
	-- compute the luminosity of the background
	local lum = color2lum(background)
	-- compute the contrast with white and black
	local wcontrast = (1 + 0.05)/(lum + 0.05)
	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
	if( background == 'FFFFFF' ) then
		return 'background-color:none;color:#' .. fontcolor .. ';'
	else
		return 'background-color:#' .. background .. ';color:#' .. fontcolor .. ';'
	end
end

local function team_table_head(args, team, ctype)
	local colors = get_colors(team, nil)
	local borderwidth = tonumber(args['border']) or 0
	-- set the default background
	local background = (ctype == 'p') and
		(colors[1] or 'FFFFFF'):upper() or
		(colors[3] or colors[2] or 'FFFFFF'):upper()
	-- now pick a font color
	local fontcolor = ''
	-- compute the luminosity of the background
	local lum = color2lum(background)
	-- compute the contrast with white and black
	local wcontrast = (1 + 0.05)/(lum + 0.05)
	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
	local s = 'background-color:#' .. background .. ';color:' .. (args['color'] or fontcolor) .. ';'
	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)

	-- set the default scheme
	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 there is no tertiary color, then pick a font color
	if (colors[3] == nil) then
		-- compute the luminosity of the background
		local lum = color2lum(colors[1])
		-- compute the contrast with white and black
		local wcontrast = (1 + 0.05)/(lum + 0.05)
		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

	-- finally build the style string
	local style = ''
	if (borderwidth > 0) then
		-- 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
			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 .. ';'
		style = style .. ' border-left: none; border-right: none;'
		style = style .. ' box-shadow: inset 0 2px 0 #FEFEFE, inset 0 -2px 0 #FEFEFE;'
	end
	style = 'background-color:#' .. background .. ';color:#' .. fontcolor .. ';' .. style

	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')
			:css('background-color', '#' .. (h or ''))
			:wikitext('&nbsp;')
		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')
			:css('background-color', '#' .. (h or ''))
			:wikitext('&nbsp;')
		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,
		',&nbsp;',
		#colornames == 2 and '&nbsp;and&nbsp;' or ',&nbsp;and&nbsp;'
	)

	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, '&nbsp;')
	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 '&nbsp;')
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()
	-- In a sandbox, preview {{#invoke:college color|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