Jump to content

Module:Portal navigation

Permanently protected module
From Meta, a Wikimedia project coordination wiki
Module documentation

Usage

This module has one method, render: {{#invoke:Portal navigation|render| ... }}.

For more information, see Template:Portal navigation/doc.

local p = {}

local function is_rtl(lang)
	lang = lang or mw.getCurrentFrame():preprocess('{{int:lang}}')
	return require('Module:Is rtl')[lang] == true
end

function get_portalicon(portalicon)
	if portalicon == nil then
		return ''
	else
		return '<span class="portal-navigation-portalicon">' .. portalicon .. '</span>'
	end
end

function converttolinearrgb(c)
	c = tonumber(c, 16)
	c = c / 255.0
	if c <= 0.03928 then
		c = c/12.92
	else
		c = ((c+0.055)/1.055) ^ 2.4
	end
	
	return c
end

function p.render(frame)
	-- Default values
	portalname = 'Portal'
	tabs = {}
	subtabs = {}
	wrc = 0

	-- Default values (customizations)
	themecolor = '#54595d'
	headerstyle = ''
	tabsicons = {}
	ff = nil
	lang = nil
	wrcadditional = 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 = value
		elseif key == 'themecolor' then
			themecolor = value
		elseif key == 'headerstyle' then
			headerstyle = value
		elseif key == 'forceflip' then
			ff = value
		elseif key == 'lang' then
			lang = value
		elseif key == 'hidenav' then
			hidenav = value
		elseif key == 'hidesubnav' then
			hidesubnav = 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, '-')
    		primetab = tonumber(id[1])
    		subtab = tonumber(id[2])
    		if subtabs[primetab] == nil then
    			subtabs[primetab] = {}
    		end
    		subtabs[primetab][subtab] = value
    	end
	end
	
	if ff == 'yes' or ff == 'true' or ff == '1' then
		ff = true
	end
	
	if hidenav == 'yes' or hidenav == 'true' or hidenav == '1' then
		hidenav = true
	end
	
	if hidesubnav == 'yes' or hidesubnav == 'true' or hidesubnav == '1' then
		hidesubnav = true
	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
	headertextcolor = '#fff'
	
	rgb = string.gsub(themecolor, '#', '')
	rgb = mw.text.split(rgb, '')
	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)
	
	luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b
	
	if luminance > 0.179 then
		headertextcolor = '#000'
	end

	-- Applying customizations to headerstyle
	headerstyle = 'background:' .. themecolor .. '; color:' .. headertextcolor .. ';'
		.. headerstyle
	
	header = '<div class="portal-navigation-header" style="' .. headerstyle .. '">'

	if ff ~= true or (ff == true and not is_rtl()) then
		header = header .. get_portalicon(portalicon) .. portalname .. '</div>'
	else
		header = header .. portalname .. get_portalicon(portalicon) .. '</div>'
	end

	if wrc == '1' or wrc == 1 or wrc == 'true' or wrc == true or wrc == 'yes' then
		badgeargs = {}
		if ff == true then
			badgeargs['forceflip'] = ff
		end
		if wrcadditional ~= nil then
			badgeargs['additional'] = wrcadditional
		end

		header = frame:expandTemplate{
			title = 'Wikimedia Resource Center badge',
			args = badgeargs }
			.. '\n\n' .. header
	end
	
	-- Constructing the rest
	-- Relevant variables: themecolor tabs tabsicons active subtabs

	body = ''

	if hidenav ~= true then
		body = body .. '<ul class="portal-navigation-body">'

		for index, pagelink in ipairs(tabs) do
			-- Open TOC entry container
			body = body .. '<li>'
			
			-- Create the tab itself
			local entryclass = 'portal-navigation-entry'
			local entrystyle = ''
			if index == active then
				if subtabs[index] == nil or hidesubnav == true then
					entrystyle = ' style="border-bottom-color:' .. themecolor .. ';"'
				else
					entryclass = entryclass .. ' portal-navigation-entry-has-subtabs'
				end
			end
			
			icon = ''
			if tabsicons[index] ~= nil then
				icon = '<span class="portal-navigation-tabicon">' .. tabsicons[index] .. '</span>'
			end
			
			body = body
				.. '<span class="' .. entryclass .. '"' .. entrystyle .. '>'
				.. icon .. pagelink
				.. '</span>'
			
			-- If the tab is active, show the subnav if there is any
			
			if index == active and subtabs[index] ~= nil and hidesubnav ~= true then
				body = body .. '<ul class="portal-navigation-subtabs" style="border-color:' .. themecolor .. ';">'
				
				for _, subpagelink in ipairs(subtabs[index]) do
					body = body .. '<li>' .. subpagelink .. '</li>'
				end
				
				body = body .. '</ul>'
			end
			
			-- Close TOC entry container
			body = body .. '</li>'
		end
	
		body = body .. '</ul>'
	end

	local templatestyles = frame:extensionTag('templatestyles', '', {src = 'Module:Portal navigation/styles.css'})

	local classes = 'portal-navigation'
	local attributes = ''
	if lang then
		attributes = ' lang="' .. lang .. '" dir="' .. (is_rtl(lang) and 'rtl' or 'ltr') .. '"'
	end
	if ff == true then
		classes = classes .. ' portal-navigation-force-' .. (is_rtl() and 'rtl' or 'ltr')
	end

	return '<div class="' .. classes .. '"' .. attributes .. '>' .. templatestyles .. header .. body .. '</div>'
end

return p