Jump to content

Module:Portal navigation: Difference between revisions

From Wikipedia, the free encyclopedia
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.render(frame)
function p._render(args)
-- Default values
local portalname = 'Portal'
local tabs = {}
local tabs = {}
local subtabs = {}
local subtabs = {}
local wrc = nil

-- Default values (customizations)
local themecolor = '#54595d'
local headerstyle = nil
local tabsicons = {}
local tabsicons = {}
-- Default values
local wrcadditional = nil
args.portalname = args.portalname or 'Portal'
local id = nil
args.themecolor = args.themecolor or '#54595d'
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
for key, value in pairs(frame:getParent().args) do
if key == 'portalname' then
portalname = value
elseif key == 'portalicon' then
portalicon = value
elseif key == 'active' then
active = tonumber(value)
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 primetab = tonumber(id[1])
local subtab = tonumber(id[2])
if subtabs[primetab] == nil then
subtabs[primetab] = {}
end
subtabs[primetab][subtab] = value
end
end
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
-- 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')
local tabindex = {}
for index, pagelink in ipairs(tabs) do
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(pagelink)
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

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