Lua

CodeDiscussionEditHistoryLinksLink count Subpages:DocumentationTestsResultsSandboxLive code All modules

Code

local p = {}  -- Tincture

-------------- locals 
local function draw(color, ss, tc, pf, gt)
	if mw.title.new('Tincture/draw' .. ss,10).exists then
		return mw.getCurrentFrame():expandTemplate{ title = 'Tincture/draw' .. ss, args = { color, gt, tc = tc, pf = pf } }
	else
		return '<strong><span style="color: red; text-decoration: inherit;">Bad color definition in [[Template:Tincture]]: '.. ss ..'</span></strong>'
	end
end -- local function draw
-- 
local function sortc ( itab, otab, ccode )
	local tinct = ccode;
	if	tinct == 'A'	then tinct = 'a';	end	-- in categories treat argent-dark like argent (2023-05-10)
	if  tinct == 'l' 
	and ss == 'CH'	then tinct = 'b';	end		--
	for i, v in ipairs(itab) do
		if v == ccode then 
			table.insert(otab, tinct)
			return true
		end
	end
	return false
end -- local function sortc
--
local function category(colors, ss, tc, cat, no_error_cat)
	return mw.getCurrentFrame():expandTemplate{ title = 'Tincture/cat' .. ss, args = { table.concat(colors, '/'), tc = tc, cat = cat, ['no error cat'] = no_error_cat and '1' or nil } }
end -- local function category
--
local function paletcat(ss, cat)
	return mw.getCurrentFrame():expandTemplate{ title = 'Tincture/catP', args = { ss, cat = cat } }
end -- local function p-category
--
local function pnotspec()
	local exp = '';
	if	mw.ustring.lower(mw.ustring.sub(mw.title.getCurrentTitle().text,-4)) ~= '.svg' then	
		exp = '_(nonSVG)';
	end
	return mw.getCurrentFrame():expandTemplate{ title = 'Igen/cat', args = {'Tincture palette not specified'..exp } }
end -- local function pnotspec
--
local function defnonsvg()
	return mw.getCurrentFrame():expandTemplate{ title = 'Igen/cat', args = {'Tinctures (Defined nonSVG)' } }
end -- local function defnonsvg
--
local function tnotspec()
	local exp = '';
	if	mw.ustring.lower(mw.ustring.sub(mw.title.getCurrentTitle().text,-4)) ~= '.svg' then	
		exp = '_(nonSVG)';
	end
--	return mw.getCurrentFrame():expandTemplate{ title = 'Igen/cat', args = {'Tinctures not specified'..exp } }
	return mw.getCurrentFrame():expandTemplate{ title = 'Igen/cat', args = {'No tincture specified'..exp } }
end -- local function tnotspec
--
local function tsuppress()
	local exp = '';
--	if	mw.ustring.lower(mw.ustring.sub(mw.title.getCurrentTitle().text,-4)) ~= '.svg' then	
--		exp = '_(nonSVG)';
--	end
	return mw.getCurrentFrame():expandTemplate{ title = 'Igen/cat', args = {'Tincture categorizing suppressed'..exp } }
end -- local function t-suppress
--
local function tinc_cat(colors)
	return mw.getCurrentFrame():expandTemplate{ title = 'Tincture/cat0', args = { table.concat(colors, '/') } }
end -- local function t-category
--
local function unab_cat(colors)			--	colors for catsort ?
	return mw.getCurrentFrame():expandTemplate{ title = 'Igen/cat', args = {'Tinctures uncategorizeable' } }
end -- local function unable to categorize

-- local function: converts 'ddd ddd ddd'  to  '#rrggbb' (or '#rgb')
local function convdh ( p1, p2, p3 )
	local lpar = {}; -- separated by either pipe, slash, minus, comma or space 
	local dect = {}
	local hext = {}
	local numb = {}
	local same = true
	lpar [1] = mw.text.trim ( p1 );
	if p3 == nil then				 -- split-pattern: REGEXP won't work
		if p2 ~= nil then 
			lpar[1] = lpar[1] .. '-' .. mw.text.trim(p2)
		end
		lpar[1] = mw.ustring.gsub (lpar[1], '-', '/', 3)
		lpar[1] = mw.ustring.gsub (lpar[1], ',', '/', 3)
		lpar[1] = mw.ustring.gsub (lpar[1], ' ', '/', 3)
		dect = mw.text.split(lpar[1] or '1/2/3', '/');
	else
		lpar [2] = mw.text.trim ( p2 );
		lpar [3] = mw.text.trim ( p3 );
		dect = lpar;
	end
	for i = 1, 3 do
		numb[i] = tonumber( dect[i] )
		if numb[i] == nil or numb[i] > 255 then
			error (i .. 'value "' .. dect[i] or '?' .. '" cannot be converted to hexadecimal')
--				..dect[1]..','..dect[2]..','..dect[3]..'.'..i)
		end
		hext [i] = mw.ustring.format ( "%X", numb[i] )
		if numb[i] < 16 then hext[i] = '0' .. hext[i] end;
		if mw.ustring.byte ( hext [i], 1 )  ~= mw.ustring.byte ( hext[i], 2 )  then
			same = false
		end
	end
	if same then 
		hext[1] = mw.ustring.sub (hext[1], 2)
		hext[2] = mw.ustring.sub (hext[2], 2)
		hext[3] = mw.ustring.sub (hext[3], 2)
	end
	return '#'..hext[1]..hext[2]..hext[3]
end -- local function convdh

--
local function cats ( titl, outs, tinc )
	if mw.ustring.find (titl, tinc .. ',') 
	or mw.ustring.find (titl, tinc .. ' ') then 
		outs = outs .. ', ' .. tinc;
	end
	return outs;	
end -- local function cats


-------------------- local / global ----------``-------------------------------
-- local / global function: converts h → d: #rrggbb or #rgb to table {rr, gg, bb}
function p.convht ( frame )
	local gpar = {};	
	local hexv =  nil;
	local hexi = '000';
	local hwxt = '0';
 	local gpar = frame.args;
 	if gpar then 
 		hexv = tostring (gpar[1]);	-- global
 	else	 
		hexv = tostring ( frame );	-- local
 	end

	hexv = mw.text.trim( hexv )
	if  mw.ustring.sub ( hexv, 1, 1 ) == '#' then 
		hexi = mw.ustring.sub (hexv, 2)
		hext = '1'
	elseif mw.ustring.sub ( hexv, 1, 3) == '\\35' then 
		hexi = mw.ustring.sub (hexv, 4)
		hext = '2'
	elseif mw.ustring.sub ( hexv, 1, 5) == '&#35;' then 
		hexi = mw.ustring.sub (hexv, 6)
		hext = '3'
	elseif mw.ustring.sub ( hexv, 1, 6) == '&#035;' then 
		hexi = mw.ustring.sub (hexv, 7)
		hext = '4'
	elseif mw.ustring.sub ( hexv, 1, 6) == '&#x23;' then 
		hexi = mw.ustring.sub (hexv, 7, #hexv)
		hext = '5'
	elseif mw.ustring.sub ( hexv, 1, 7) == '&#x023;' then 
		hexi = mw.ustring.sub (hexv, 8, #hexv)
		hext = '6'
	else	
		hext = '9'
		error ('value "' .. hexv .. '" cannot be converted to decimal ' .. #hexv )
	end
    if #hexi ~= 3 and #hexi ~= 6 then
		error ('value "' .. hexi .. '" with length ' .. #hexi .. ' are invalid' )
	end
--	error ('value "' .. hexv .. '" type ' .. hext .. ' = ' .. hexi)
	local dec  =  {};
	for i = 1, 3 do
		if #hexi == 3 then
			dec [i] = tonumber ( mw.ustring.sub (hexi, i, i)..mw.ustring.sub (hexi, i, i), 16 ) 
		else
			dec [i] = tonumber ( mw.ustring.sub (hexi, 2*i - 1, 2*i), 16 ) 
		end
	end	
	return dec;
end -- function convht

-- local / global function: converts h ← d '#rrggbb' or '#rgb' and returns 'ddd ddd ddd'
function p.convhd ( frame )
	local gpar = frame.args;
	if gpar then decval = p.convht (gpar[1]);	-- global
		else	 decval = p.convht ( frame );	-- local
	end
	return decval[1]..' '..decval[2]..' '..decval[3]
end -- function convhd

-- local / global function: converts h → d'#rrggbb' or '#rgb' and returns 'ddd ddd ddd' formatted
function p.convhdf ( frame )
	local gpar = frame.args;
	if gpar then dtab = p.convht (gpar[1]);	-- global
			else dtab = p.convht ( frame );	-- local
	end
	local dtxt = '&nbsp;'
	for i = 1, 3 do
		if dtab[i] < 100 then
			if dtab[i] < 10 then 
				dtxt = dtxt .. ' '
			end
			dtxt = dtxt .. '&nbsp;'
		end
		dtxt = dtxt .. ' ' .. tostring ( dtab [i] ) 
	end
	local contrast = '0';
	if  dtab [1] + dtab [2] + dtab [3] < 400 then 
		  contrast = 'F'; 
	end
-- TEST ----------
--	local contval = dtab [1] + dtab [2] + dtab [3]
-- 	contrast = contrast .. ' - ';
--	if contval < 100 then
--		if contval < 10 then 
--			contrast = contrast .. '&nbsp;'
--		end
--		contrast = contrast .. '&nbsp;'
--	end
-- 	contrast = contrast .. tostring ( contval ); 
-- TEST ----------
	dtxt = contrast .. dtxt; 
	return dtxt
end -- function convhdf

-- global function returns contrast color
function p.titcolor ( frame )
	local gpar = frame.args
	local decval = p.convhdf ( gpar[1] );
	if mw.ustring.sub ( decval, 1, 1 ) == 'F'
		then return 'FFF'
		else return '000'
	end
end -- function titcolor - does not work perfectly

-- global function tbcbox: returns a Tbc box
function p.tbcbox ( frame )
	local gpar = frame.args
	local hstr = convdh ( gpar[1], gpar[2], gpar[3] )	
	return frame:expandTemplate { title = 'colorbox', args = { hstr, title = '"' .. hstr ..'"' } }
end -- function tbxbox

-- global function convgpl: gets #rgb, contrast, name; returns line formatted
function p.convgpl ( frame )
	local gpar = frame.args;
	local line = p.convhdf ( gpar [1] );						-- convert #rgb  
	local expl = mw.ustring.sub ( line, 2) .. ' ' .. gpar [1];	-- d d d   #rgb
	if #gpar[1] == 4 then
		expl = expl .. '&nbsp; &nbsp;'
	end
	local contrast = gpar [2] or '#001'
	expl = expl .. ' '				--	.. contrast;								-- contrast		-test 
--	if mw.ustring.sub ( contrast, 2, 2) == mw.ustring.sub ( line, 1, 1) 
--		then	expl = expl .. ' '	--	'{{mono|1= }}'
--		else	expl = expl .. '·'	--	'{{mono|1=·}}''
--	end
	expl = expl .. gpar [3];									-- name
	return expl
end -- function convgpl

-- global function convert:  gets 3 num, returns hex and dec formatted
function p.convert ( frame )
	local gpar = frame.args;
	local hcod = convdh ( gpar[1], gpar[2], gpar[3] );
	local fnum = p.convhdf (hcod)
	return '&#35;' .. mw.ustring.sub ( hcod, 2 ) .. mw.ustring.sub ( fnum, 2);
end -- function convert

--  ============================================================================
--  ============================================================================
--  main function tincture
function p.main (frame)
	local getArgs = require( 'Module:Arguments' ).getArgs
	local args = getArgs(frame)
	   ss = args.ss  or '0'
	if ss == '≈' then ss = '0' end
	local top = ''
	if args.s == 'f' then top = 'flag ' end
	local cm = args.cm or ' ';
	local tc = args.tc
	local pf = args.pf
	local gt = args.gpltab or ""
	local align = 'tincturebox-left'
	local InFi = (args['+'] == '+')
	local cols = args
	local tincunt = 0;
	local colors = {}
	local box = {}
	local tab = {}
	local out = {}
	local ordtab = { }
--	local ssytab = { ' ',  }	--	table of all palettes: catyes
--	local ssntab = { '0',  }	--	table of all palettes: catnot
	local gpltab = false
	local insert = false
	local gennot = false		--	generell   = don't t-cat
	local genyes = true			--	generell   = force t-cat
	local catnot = false		--	indiv. '-' = don't t-cat
	local catyes = false		--	indiv. '*' = force t-cat
	local catimp = false		--	indiv. '?' = not t-categorizeable 		
	local nopcat = false		--	indiv. '-' = don't p-cat
	
	if gt == "" then 
		if mw.title.getCurrentTitle().namespace == 4 then gt = '3' 
		else gt = '1'
		end
	end
	if gt == "2" or gt == "3" then
		InFi   = true
		gpltab = true
	end
	if cols.ss	then
		ss =  cols.ss 
	end 	

	if type(args[1]) == 'string' and args[1]:sub(1, 6) == '<table' then
		return args[1]
	end

	if args[2] == nil  then
		cols = mw.text.split(args[1] or '', '%s*/%s*')
	end
	for _, v in ipairs(cols) do
		if not v or v == '' then
			break			--	empty par
		elseif v == '-' then
			   v =  '0'		--  t-cat suppression
			   catnot = true
		elseif v == '~' then
			   v =  '0'		--  p-cat suppression
			   nopcat = true
		elseif v == '*' then
			   v =  '0'		--  t-cat forcing
			   catyes = true
		elseif v == '?' then
			   v =  '0'		--  not t-catable
			   catimp = true
		elseif v == '+' then
			InFi = true
		elseif mw.ustring.sub( v, 1, 3 ) == 'ss=' then  -- any case when ss=
			ss =  mw.ustring.sub( v, 4 )
		elseif mw.ustring.len( v ) >= 2 
		   and v == mw.ustring.upper( v ) then  --	belongs to character class %u
				ss = v							--	tincture palette
		else
			table.insert(colors, v)				--	it's a tincture 
			tincunt = tincunt + 1
		end
	end

	ss = mw.ustring.upper( ss )					--	final formatting
----			general yes/not depending on ss
--	for i = 1, #ssytab do			--	force the specified palette ?
--		if ss == ssytab [i] then genyes = true; end 
--	end
--	for i = 1, #ssntab do			--	exclude the specified palette ?
--		if ss == ssntab [i] then gennot = true; end 
--	end
	if	args.el == "y" then gennot = true; end	--	exclude coa elements 
--				indiv. precedes gener.
	if	catnot == false	then
		if	catyes == false	then				--	expl. indiv. "yes" ?
			catnot  = gennot 
		end
	end
	if	catyes == false	then
		catyes  = genyes
	end

--  0) headline and boxes
	if gt == "2" or gt =="3" then
		table.insert(out, frame:expandTemplate{title='=', args={'<h4>GPLtab '..draw('gpltabnam',ss,'','','tab')..'</h4>'}})
	end
	for i, v in ipairs(colors) do
		box[i] = draw(v, ss, tc, pf, 'box')
	end

-- 1) categories: p_cat, t_cat
	if	gpltab == false					--	either palette or tincture
	and args.ns == "6" then			
		if	nopcat ~= true	then		--	when not suppressed:
			if	ss ~= '0'	then		--	Palette def	(^GN)
				table.insert(box, paletcat( ss, args.cat ))
				if	mw.ustring.lower(mw.ustring.sub(mw.title.getCurrentTitle().text,-4)) ~= '.svg' then	
					table.insert(box, defnonsvg() )
				end
			else						--	Palette not specified
				if	args.el ~= "y" 
				and	catimp	== 	false 
				and	tincunt ~= 0	then
					table.insert(box, pnotspec() )
				end
			end
		end
										--	Tincture categorizaton
		if	catnot == true then   		--	suppressed ?
			if args.el ~= "y" then		--	when not an element
				table.insert(box, tsuppress() )		--	categorization suppressed
			end
		else
			if	catimp == true then 	--	cat impossible ?
				table.insert(box, unab_cat() )		--	categorizationt unable
			elseif tincunt > 0 then		--	sorted table
				insort = sortc (colors, ordtab, 'a' )
				insort = sortc (colors, ordtab, 'A' )
				insort = sortc (colors, ordtab, 'o' )
				insort = sortc (colors, ordtab, 'b' )
				insort = sortc (colors, ordtab, 'B' )
				insort = sortc (colors, ordtab, 'l' )	--	l-azure (CH)
				insort = sortc (colors, ordtab, 'c' )
				insort = sortc (colors, ordtab, 'C' )
				insort = sortc (colors, ordtab, 'e' )	--	(h)ermine
				insort = sortc (colors, ordtab, 'g' )
				insort = sortc (colors, ordtab, 'm' )	--	multicolor
				insort = sortc (colors, ordtab, 'n' )
				insort = sortc (colors, ordtab, 'p' )
				insort = sortc (colors, ordtab, 's' )
				insort = sortc (colors, ordtab, 't' )
				insort = sortc (colors, ordtab, 'T' )
				insort = sortc (colors, ordtab, 'v' )
				insort = sortc (colors, ordtab, 'V' )	--	vair, fur
				insort = sortc (colors, ordtab, 'x' )
				table.insert(box, tinc_cat(ordtab))	--	std tincture cat
			else						--	tincunt	= zero:
				table.insert(box, tnotspec() )
			end							--	catimp false & tincunt > 0
		end								--	catnot false
	end									--	gpltab false

-- 2) box
	if gt == "1" or gt =="3" then
		if args.align == 'right' or args.align == 'center' then
			align = 'tincturebox-' .. align
		end
		local frame = mw.getCurrentFrame()
		text = frame:extensionTag('templatestyles', '', { src = 'Tincture/styles.css' }) ..
			'<div class="tincturebox ' .. align .. '">' .. table.concat(box) .. cm .. '</div>'
		if InFi then
			local name = mw.getContentLanguage():ucfirst(frame:expandTemplate{ title = 'I18n/COA', args = { top .. 'tincture' } })
			local link = ' <small>([[Template:Tincture/draw'..ss..'|'..ss..']])</small>'
			if ss ~= '' and ss ~= '0' then name = name .. link end 
			table.insert(out, frame:expandTemplate{ title = 'InFi', args = { name, text } })
		else
			table.insert(out, text )
		end
	end
	
-- 3) tab
	if gt == "2" or gt =="3" then
		table.insert(out, frame:expandTemplate{ title = '=', args = { "&#35;<br>" } })
		for i, v in ipairs(colors) do
			table.insert(out, draw( v, ss, tc, pf, 'tab') ) 
		end
		table.insert(out, frame:expandTemplate{ title = '=', args = { "<br><br>" } })
	end
	return table.concat(out)
end -- function main / tincture 


--  main function: create sorted tincture categories
function p.cstc (frame)
	local titl = mw.ustring.lower( mw.title.getCurrentTitle().text )
	local outs = ''
	
	outs = cats (titl, outs, 'argent' )
	outs = cats (titl, outs, 'argent-dark' )
	outs = cats (titl, outs, 'or' )
	outs = cats (titl, outs, 'azure' )
	outs = cats (titl, outs, 'brunâtre' )	-- +
	outs = cats (titl, outs, 'céleste' )
	outs = cats (titl, outs, 'carnation' )
	outs = cats (titl, outs, 'cendrée' )
	outs = cats (titl, outs, 'ermine' )
	outs = cats (titl, outs, 'gules' )
--	outs = cats (titl, outs, 'multiple' )
	outs = cats (titl, outs, 'murrey' )		-- +
	outs = cats (titl, outs, 'naranja' )
	outs = cats (titl, outs, 'orange_t' )	-- + +
	outs = cats (titl, outs, 'purpure' )
	outs = cats (titl, outs, 'sable' )
	outs = cats (titl, outs, 'sanguine' )	-- +
--	outs = cats (titl, outs, 'tawny' )		-- +?
	outs = cats (titl, outs, 'tenné' )
	outs = cats (titl, outs, 'vert' )
	outs = cats (titl, outs, 'vair' )
	outs = cats (titl, outs, 'invisible' )
	
	outs = mw.ustring.upper( mw.ustring.sub( outs, 3, 3 ) ) .. mw.ustring.sub( outs, 4 ) .. ' in heraldry'
	if mw.ustring.gsub( outs, ', ', '? ' ) == mw.ustring.gsub( outs, ', ', '? ', 1 ) then
		outs = mw.ustring.gsub( outs, ', ', ' and ' );	-- "and" when only two colors
	end
	return outs	
end -- cstc

return p;