Module:College color/sandbox: Difference between revisions

Content deleted Content added
Jackmcbarn (talk | contribs)
add error checking to color2lum
sync
 
(22 intermediate revisions by 7 users not shown)
Line 1:
--
-- This module implements {{CollegePrimaryHex}}, {{CollegePrimaryStyle}},
-- {{CollegePrimaryColorLink}}, {{CollegeSecondaryHex}},
-- {{CollegeSecondaryStyle}}, {{CollegeSecondaryColorLink}}, and {{NCAA color}}
--
Line 8:
local data_module = "Module:College color/data"
 
local function sRGB stripwhitespace( v text)
return text:match("^%s*(.-)%s*$")
if (v <= 0.03928) then
end
return v / 12.92
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
returnv = math.pow((v+0.055)/1.055, 2.4)
end
return v
end
local function color2lum( origc )
local c = origc:matchstripwhitespace(origc or '^%s*#?([A-Fa-f0-9]+)%s*$'):lower()
 
if not c then
-- remove leading # (if there is one)
error('Invalid hex color ' .. origc, 2)
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
 
local cs = mw.text.split(c, '')
-- failure
local R, G, B
error('Invalid hex color ' .. origc, 2)
if #cs == 6 then
R = sRGB( tonumber(cs[1] .. cs[2], 16)/255 )
G = sRGB( tonumber(cs[3] .. cs[4], 16)/255 )
B = sRGB( tonumber(cs[5] .. cs[6], 16)/255 )
elseif #cs == 3 then
R = sRGB( tonumber(cs[1], 16)/15 )
G = sRGB( tonumber(cs[2], 16)/15 )
B = sRGB( tonumber(cs[3], 16)/15 )
else
error('Wrong number of hex digits in color ' .. origc, 2)
end
return 0.2126 * R + 0.7152 * G + 0.0722 * B
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, " [Ff]ootball$", '')
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, " [VvSs]ollyballwim$", '')
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$", '')
Line 49 ⟶ 82:
end
local function get_colors(team, unknown)
team = mw.text.trimstripwhitespace(team or '')
unknown = unknown or {"DCDCDC", "000000"}
 
local use_default = {
[""] = 1,
Line 57 ⟶ 90:
["free agent"] = 1,
}
 
local colors = nil
 
if ( team and use_default[team:lower()] ) then
colors = {"DCDCDC", "000000"}
Line 87 ⟶ 120:
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
Line 96 ⟶ 142:
borderwidth = tonumber(borderwidth or '2') or 0
if (borderwidth > 0 and color ~= '#FFFFFF') then
style = style .. ' border:' ..bordercss(color, borderwidth .. 'px solid ' .. color .. ';')
end
 
return style
end
Line 104 ⟶ 150:
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
Line 113 ⟶ 172:
borderwidth = tonumber(borderwidth or '2') or 0
if (borderwidth > 0 and color ~= '#FFFFFF') then
style = style .. ' border:' ..bordercss(color, borderwidth .. 'px solid ' .. color .. ';')
end
 
return style
end
Line 154 ⟶ 213:
-- do not add a border if it's nearly white
if ((1 + 0.05)/(color2lum(bordercolor) + 0.05) >= 1.25) then
style = style .. bordercss(' border:' .. borderwidth .. 'px solid #' .. bordercolor, .. ';'borderwidth)
end
end
Line 191 ⟶ 250:
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 ''
Line 201 ⟶ 308:
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
Line 234 ⟶ 341:
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
 
Line 242 ⟶ 391:
local r = mw.html.create('')
r:tag('span')
:addClass('legend-color')
:css('background-color', '#' .. (h or ''))
:wikitext('&nbsp;')
:css('border', '1px solid #000')
:wikitext('&nbsp;&nbsp;&nbsp;&nbsp;')
return tostring(r)
end
Line 253 ⟶ 402:
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'}
for i=1,5 do
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
Line 273 ⟶ 428:
 
local res = ''
if (#colornames ==> 10) then
rescolornames[1] = ucfirst(colornames[1] )
elseif (#colornames == 2) then
res = colornames[1] .. '&nbsp;and&nbsp;' .. colornames[2]
else
res = colornames[1]
for i=2,#colornames do
if( i < #colornames ) then
res = res .. ',&nbsp;' .. colornames[i]
else
res = res .. ',&nbsp;and&nbsp;' .. colornames[i]
end
end
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>')
Line 297 ⟶ 447:
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
Line 351 ⟶ 502:
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
 
Line 356 ⟶ 517:
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
Line 367 ⟶ 534:
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