Module:Tincture

local p = {} -- Tincture

-- locals local function draw(color, ss, tc, pf, gt) return mw.getCurrentFrame:expandTemplate{ title = 'Tincture/draw' .. ss, args = { color, gt, tc = tc, pf = pf } } end -- local function draw -- local function sortc ( itab, otab, ccode ) for i, v in ipairs(itab) do		if v == ccode then table.insert(otab, v)			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: 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 / 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 = ' ' for i = 1, 3 do		if dtab[i] < 100 then if dtab[i] < 10 then dtxt = dtxt .. ' '			end dtxt = dtxt .. ' '		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 .. ' ' --		end --		contrast = contrast .. ' ' --	end -- 	contrast = contrast .. tostring ( contval ); -- TEST -- dtxt = contrast .. dtxt; return dtxt end -- function convhdf

-- 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

-- 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 .. '  '	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 .. ' ' else	expl = expl .. '·' 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) local ss = args.ss or '0' if ss == '≈' then ss = '0' end local tc = args.tc	local pf = args.pf	local gt = args.gpltab or "" local align = 'tincturebox-left' local error_cat = true local InFi = (args['+'] == '+') local cols = args local colors = {} local box = {} local tab = {} local out = {} local ordtab = { } local insert = false

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 error_cat = false end

ss = mw.ustring.upper( ss ) 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 if cols.ss	then ss = mw.ustring.upper( cols.ss ) end for _, v in ipairs(cols) do		if not v or v == '' then break elseif v == '-' then error_cat = false elseif v == '+' then InFi = true elseif mw.ustring.sub( v, 1, 3 ) == 'ss=' then -- any case when ss= ss = mw.ustring.upper( 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		else table.insert(colors, v)		end end -- 0) headline and boxes	if gt == "2" or gt =="3" then		table.insert(out, frame:expandTemplate{title='=', args={' GPLtab '..draw('gpltabnam',ss,,,'tab')..' '}})	end	for i, v in ipairs(colors) do		box[i] = draw(v, ss, tc, pf, 'box')	end

-- 1) cat: sorted table	if error_cat == true then		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, 'c' )		insort = sortc (colors, ordtab, 'C' )		insort = sortc (colors, ordtab, 'g' )		insort = sortc (colors, ordtab, 'n' )		insort = sortc (colors, ordtab, 'p' )		insort = sortc (colors, ordtab, 's' )		insort = sortc (colors, ordtab, 't' )		insort = sortc (colors, ordtab, 'v' )		insort = sortc (colors, ordtab, 'x' )		table.insert(box, category(ordtab, ss, tc, args.cat, no_error_cat))	end -- 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' }) .. ' ' .. table.concat(box) .. ' '		if InFi then local name = mw.getContentLanguage:ucfirst(frame:expandTemplate{ title = 'I18n/COA', args = { 'tincture' } }) local link = ' ('..ss..') ' 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; " } })		for i, v in ipairs(colors) do			table.insert(out, draw( v, ss, tc, pf, 'tab') ) 		end		table.insert(out, frame:expandTemplate{ title = '=', args = { " " } })	end	return table.concat(out) end -- function main / tincture

return p;