Module:Portal navigation: Difference between revisions
Appearance
Content deleted Content added
cleanup wrc code |
cleanup argument handling |
||
Line 1: | Line 1: | ||
require('strict') |
require('strict') |
||
local p = {} |
local p = {} |
||
local getArgs = require('Module:Arguments').getArgs |
|||
local yesno = require("Module:Yesno") |
local yesno = require("Module:Yesno") |
||
Line 26: | Line 27: | ||
end |
end |
||
function p. |
function p._render(args) |
||
⚫ | |||
⚫ | |||
local tabs = {} |
local tabs = {} |
||
local subtabs = {} |
local subtabs = {} |
||
⚫ | |||
-- Default values (customizations) |
|||
⚫ | |||
local headerstyle = nil |
|||
local tabsicons = {} |
local tabsicons = {} |
||
⚫ | |||
local wrcadditional = nil |
|||
⚫ | |||
local id = nil |
|||
⚫ | |||
local active = nil |
|||
for _, key in ipairs({'wrc','hidenav','hidesubnav'}) do |
|||
local portalicon = nil |
|||
args[key] = yesno(args[key]) |
|||
local hidenav = nil |
|||
local hidesubnav = nil |
|||
-- Populating variables |
|||
⚫ | |||
if key == 'portalname' then |
|||
⚫ | |||
elseif key == 'portalicon' then |
|||
⚫ | |||
elseif key == 'active' then |
|||
⚫ | |||
elseif key == 'wrc' then |
|||
wrc = yesno(value) |
|||
elseif key == 'themecolor' then |
|||
themecolor = value |
|||
elseif key == 'headerstyle' then |
|||
headerstyle = value |
|||
elseif key == 'hidenav' then |
|||
hidenav = yesno(value) |
|||
elseif key == 'hidesubnav' then |
|||
hidesubnav = yesno(value) |
|||
elseif key == 'wrcadditional' then |
|||
wrcadditional = value |
|||
elseif string.find(key, 'tab') ~= nil |
|||
and string.find(key, 'subtab') == nil then -- matches tab1, tab2, ... |
|||
id = string.gsub(key, 'tab', '') |
|||
id = tonumber(id) |
|||
tabs[id] = value |
|||
elseif string.find(key, 'icon') ~= nil then -- matches icon1, icon2, etc. |
|||
id = string.gsub(key, 'icon', '') |
|||
id = tonumber(id) |
|||
tabsicons[id] = value |
|||
elseif string.find(key, 'subtab') ~= nil then -- matches subtab1-1, etc. |
|||
id = string.gsub(key, 'subtab', '') |
|||
-- Subtab params take the form [prime tab]-[sub tab] |
|||
id = mw.text.split(id, '-') |
|||
⚫ | |||
local subtab = tonumber(id[2]) |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
end |
end |
||
args.active = tonumber(args.active) |
|||
⚫ | |||
local id = tonumber(mw.ustring.match(key,'^tab(%d+)$')) |
|||
if id then |
|||
⚫ | |||
else |
|||
id = tonumber(mw.ustring.match(key,'^icon(%d+)$')) |
|||
if id then |
|||
⚫ | |||
else |
|||
local primetab, subtab = mw.ustring.match(key,'^subtab(%d+)-(%d+)$') |
|||
if primetab and subtab then |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
end |
|||
end |
|||
end |
|||
-- Constructing header |
-- Constructing header |
||
-- Relevant variables: portalname, wrc, themecolor, headerstyle |
-- Relevant variables: portalname, wrc, themecolor, headerstyle |
||
Line 92: | Line 66: | ||
-- https://stackoverflow.com/questions/3942878/how-to-decide-font-color-in-white-or-black-depending-on-background-color |
-- https://stackoverflow.com/questions/3942878/how-to-decide-font-color-in-white-or-black-depending-on-background-color |
||
local rgb = string.gsub(themecolor, '#', '') |
local rgb = string.gsub(args.themecolor, '#', '') |
||
rgb = mw.text.split(rgb, '') |
rgb = mw.text.split(rgb, '') |
||
local r, g, b |
local r, g, b |
||
Line 111: | Line 85: | ||
local root = mw.html.create('div') |
local root = mw.html.create('div') |
||
if wrc then |
if args.wrc then |
||
badgeargs = {} |
badgeargs = {} |
||
if wrcadditional then |
if wrcadditional then |
||
badgeargs['additional'] = wrcadditional |
badgeargs['additional'] = args.wrcadditional |
||
end |
end |
||
Line 127: | Line 101: | ||
header:css('font-weight','bold') |
header:css('font-weight','bold') |
||
header:css('padding','0.25em') |
header:css('padding','0.25em') |
||
header:css('background',themecolor) |
header:css('background',args.themecolor) |
||
header:css('color',luminance > 0.179 and '#000' or '#fff') |
header:css('color',luminance > 0.179 and '#000' or '#fff') |
||
header:cssText(headerstyle) |
header:cssText(args.headerstyle) |
||
header:wikitext(portalname) |
header:wikitext(args.portalname) |
||
header = get_portalicon(portalicon, header) |
header = get_portalicon(args.portalicon, header) |
||
-- Constructing the rest |
-- Constructing the rest |
||
Line 137: | Line 111: | ||
if not hidenav then |
if not args.hidenav then |
||
local body = root:tag('div') |
local body = root:tag('div') |
||
body:css('font-size','1.125em') |
body:css('font-size','1.125em') |
||
body:css('margin-bottom','1.125em') |
body:css('margin-bottom','1.125em') |
||
⚫ | |||
for index, |
for index, _ in pairs(tabs) do |
||
table.insert(tabindex,index) |
|||
end |
|||
table.sort(tabindex) |
|||
for _, index in ipairs(tabindex) do |
|||
local container = body:tag('div') |
local container = body:tag('div') |
||
container:css('display','inline-block') |
container:css('display','inline-block') |
||
Line 155: | Line 135: | ||
-- Create the tab itself |
-- Create the tab itself |
||
if index == active then |
if index == args.active then |
||
if not subtabs[index] or hidesubnav then |
if not subtabs[index] or args.hidesubnav then |
||
entry:css('border-bottom','0.3em solid '..themecolor) |
entry:css('border-bottom','0.3em solid '..args.themecolor) |
||
else |
else |
||
entry:css('margin-bottom','0') |
entry:css('margin-bottom','0') |
||
Line 170: | Line 150: | ||
icon:wikitext(tabsicons[index]) |
icon:wikitext(tabsicons[index]) |
||
end |
end |
||
entry:wikitext( |
entry:wikitext(tabs[index]) |
||
-- If the tab is active, show the subnav if there is any |
-- If the tab is active, show the subnav if there is any |
||
if index == active and subtabs[index] and not hidesubnav then |
if index == args.active and subtabs[index] and not args.hidesubnav then |
||
local subnav = container:tag('ul') |
local subnav = container:tag('ul') |
||
subnav:css('font-size','95%') |
subnav:css('font-size','95%') |
||
subnav:css('margin','0 1em') |
subnav:css('margin','0 1em') |
||
subnav:css('padding','1.125em 0') |
subnav:css('padding','1.125em 0') |
||
local borderColor = '0.35em solid'..themecolor |
local borderColor = '0.35em solid'..args.themecolor |
||
subnav:css('border-top',borderColor) |
subnav:css('border-top',borderColor) |
||
subnav:css('border-bottom',borderColor) |
subnav:css('border-bottom',borderColor) |
||
Line 194: | Line 174: | ||
clear:css('clear','both') |
clear:css('clear','both') |
||
return tostring(root) |
return tostring(root) |
||
end |
|||
function p.render(frame) |
|||
local args = getArgs(frame) |
|||
return p._render(args) |
|||
end |
end |
||
Revision as of 13:09, 7 January 2023
This module has one method, render: {{#invoke:Portal navigation|render| ... }}
.
For more information, see Template:Portal navigation/doc. For test cases, see Template:Portal navigation/testcases.
require('strict')
local p = {}
local getArgs = require('Module:Arguments').getArgs
local yesno = require("Module:Yesno")
local function get_portalicon(portalicon, root)
if portalicon then
local span = root:tag('span')
span:css('padding','0.3em')
span:css('display','inline-block')
span:css('margin-right','0.5em')
span:wikitext(portalicon)
end
return root
end
local function converttolinearrgb(c)
c = tonumber(c, 16)
c = c / 255.0
if c <= 0.03928 then
c = c/12.92321 -- Correct constant from sRGB standard
else
c = ((c+0.055)/1.055) ^ 2.4
end
return c
end
function p._render(args)
local tabs = {}
local subtabs = {}
local tabsicons = {}
-- Default values
args.portalname = args.portalname or 'Portal'
args.themecolor = args.themecolor or '#54595d'
for _, key in ipairs({'wrc','hidenav','hidesubnav'}) do
args[key] = yesno(args[key])
end
args.active = tonumber(args.active)
for key, value in pairs(args) do
local id = tonumber(mw.ustring.match(key,'^tab(%d+)$'))
if id then
tabs[id] = value
else
id = tonumber(mw.ustring.match(key,'^icon(%d+)$'))
if id then
tabsicons[id] = value
else
local primetab, subtab = mw.ustring.match(key,'^subtab(%d+)-(%d+)$')
if primetab and subtab then
primetab = tonumber(primetab)
subtab = tonumber(subtab)
if not subtabs[primetab] then
subtabs[primetab] = {}
end
subtabs[primetab][subtab] = value
end
end
end
end
-- Constructing header
-- Relevant variables: portalname, wrc, themecolor, headerstyle
-- The text color in the header is automatically chosen based on the best contrast
-- https://stackoverflow.com/questions/3942878/how-to-decide-font-color-in-white-or-black-depending-on-background-color
local rgb = string.gsub(args.themecolor, '#', '')
rgb = mw.text.split(rgb, '')
local r, g, b
if #rgb == 6 then
r = rgb[1] .. rgb[2]
g = rgb[3] .. rgb[4]
b = rgb[5] .. rgb[6]
elseif #rgb == 3 then
r = rgb[1] .. rgb[1]
g = rgb[2] .. rgb[2]
b = rgb[3] .. rgb[3]
end
r = converttolinearrgb(r)
g = converttolinearrgb(g)
b = converttolinearrgb(b)
local luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b
local root = mw.html.create('div')
if args.wrc then
badgeargs = {}
if wrcadditional then
badgeargs['additional'] = args.wrcadditional
end
root:wikitext(frame:expandTemplate{
title = 'Wikimedia Resource Center badge',
args = badgeargs })
end
local header = root:tag('div')
header:css('font-size','1.6875em')
header:css('border-radius','2px')
header:css('font-weight','bold')
header:css('padding','0.25em')
header:css('background',args.themecolor)
header:css('color',luminance > 0.179 and '#000' or '#fff')
header:cssText(args.headerstyle)
header:wikitext(args.portalname)
header = get_portalicon(args.portalicon, header)
-- Constructing the rest
-- Relevant variables: themecolor tabs tabsicons active subtabs
if not args.hidenav then
local body = root:tag('div')
body:css('font-size','1.125em')
body:css('margin-bottom','1.125em')
local tabindex = {}
for index, _ in pairs(tabs) do
table.insert(tabindex,index)
end
table.sort(tabindex)
for _, index in ipairs(tabindex) do
local container = body:tag('div')
container:css('display','inline-block')
container:css('position','relative')
container:css('vertical-align','top')
local entry = container:tag('span')
entry:css('display','inline-block')
entry:css('margin','1em')
entry:css('padding-bottom','0.5em')
entry:css('font-weight','bold')
-- Create the tab itself
if index == args.active then
if not subtabs[index] or args.hidesubnav then
entry:css('border-bottom','0.3em solid '..args.themecolor)
else
entry:css('margin-bottom','0')
end
else
entry:css('border-bottom','0.3em solid #c8ccd1')
end
if tabsicons[index] then
local icon = entry:tag('span')
icon:css('margin-right','0.75em')
icon:wikitext(tabsicons[index])
end
entry:wikitext(tabs[index])
-- If the tab is active, show the subnav if there is any
if index == args.active and subtabs[index] and not args.hidesubnav then
local subnav = container:tag('ul')
subnav:css('font-size','95%')
subnav:css('margin','0 1em')
subnav:css('padding','1.125em 0')
local borderColor = '0.35em solid'..args.themecolor
subnav:css('border-top',borderColor)
subnav:css('border-bottom',borderColor)
subnav:css('list-style','none')
for _, subpagelink in ipairs(subtabs[index]) do
local link = subnav:tag('li')
link:css('margin','0')
link:wikitext(subpagelink)
end
end
end
end
local clear = root:tag('div')
clear:css('clear','both')
return tostring(root)
end
function p.render(frame)
local args = getArgs(frame)
return p._render(args)
end
return p