Module:SimpleArgs
Documentation for this module may be created at Module:SimpleArgs/doc
local p = {}
--[[
Version 2020-08-28
1. Get parameters (whether the parameters are called with #invoke or from a template)
2. Get parameters (of several types with their verification) from frame parameters.
ParId parameter is identified by a position (1, 2, 3 ... ), single name (|name= |other name=) or table of two names for each parameter.
This last options is used in translations that retain the original language (or main), usually English, i.e.:
local keywords = { -- in this case with Spanish
name = {'name', 'nombre'},
other name = {'other name', 'otro nombre'},
}
Then the parameter can be obtained with p.GetStr_Par (Args, keywords[name])
--]]
local RS = {
NotFoundArgName = 'NotFoundArgName',
SIsNotNumber = 'SIsNotNumber',
NIsNotPosNumber = 'NIsNotPosNumber',
NIsNotZeroOrPosNumber = 'NIsNotZeroOrPosNumber',
NIsNotInt = 'NIsNotInt',
NIsNotInRange = 'NIsNotInRange',
NIsLessThan = 'NIsLessThan',
NIsGreaterThan = 'NIsGreaterThan',
InvalColorLength = 'InvalColorLength',
InvalColorChar = 'InvalColorChar',
InvalColorName = 'InvalColorName',
STabIsNotInRange = 'STabIsNotInRange',
STabFewItems = 'STabFewItems',
SIsNotAssigned = 'SIsNotAssigned',
CharNotFoundInPattern = 'CharNotFoundInPattern',
SNotFoundInTab = 'SNotFoundInTab',
EmptyValue = 'EmptyValue',
SizeUnitRequired = 'SizeUnitRequired',
InvalSizeUnit = 'InvalSizeUnit',
SizeWithoutNumber = 'SizeWithoutNumber',
InvalAlign = 'InvalAlign',
InvalBool = 'InvalBool',
left = 'left',
right = 'right',
top = 'top',
bottom = 'bottom',
center = 'center',
Yes = 'Yes',
No = 'No',
PossibleValues = 'PossibleValues',
}
local SD = require('Module:SimpleDebug')
local I18n = 'SimpleArgs'
local i18n = {
[RS.NotFoundArgName] = "The parameter name \"$1\" is invalid",
[RS.SIsNotNumber] = "\"$1\" is not a number",
[RS.NIsNotPosNumber] = "$1 is not a positive number",
[RS.NIsNotZeroOrPosNumber] = "$1 is not zero or a positive number",
[RS.NIsNotInt] = "$1 is not an integer.",
[RS.NIsNotInRange] = "$1 is not between $2 and $3",
[RS.NIsLessThan] = "$1 is less than $2",
[RS.NIsGreaterThan] = "$1 is greater than $2",
[RS.InvalColorLength] = 'Invalid color code length, after "#", 6 valid characters (0-F) are required (found "$1")',
[RS.InvalColorChar] = 'Invalid character in the code color (from "$1")',
[RS.InvalColorName] = 'Color name ($1) is not a valid HTML color name',
[RS.STabIsNotInRange] = "The item number ($1) is not between $2 and $3",
[RS.STabFewItems] = "There are too few elements ($1), at least $2 are required",
[RS.SIsNotAssigned] = "Required parameter is missing",
[RS.CharNotFoundInPattern] = "\"$1\" is not a character of \"$2\"",
[RS.SNotFoundInTab] = "\"$1\" is not found in \"$2\"",
[RS.EmptyValue] = "\"$1\" has not a value",
[RS.SizeUnitRequired] = "Size unit required (em, px or %)",
[RS.InvalSizeUnit] = "Invalid unit ($1)",
[RS.SizeWithoutNumber] = "Without number",
[RS.InvalAlign] = "Invalid alignment ($1)",
[RS.InvalBool] = "Invalid boolean ($1)",
[RS.left] = "left",
[RS.right] = "right",
[RS.top] = "top",
[RS.bottom] = "bottom",
[RS.center] = "center",
[RS.Yes] = "yes|y|true|t|1",
[RS.No] = "no|n|false|f|0",
[RS.PossibleValues] = "Possible values: $1",
}
function p.HasValue (v)
return (v ~= nil) and (v ~= '')
end
--http://lua-users.org/wiki/CopyTable:
function p.deep_copy_table (orig)
local orig_type = type(orig)
local copy
if orig_type == 'table' then
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[p.deep_copy_table(orig_key)] = p.deep_copy_table(orig_value)
end
setmetatable(copy, p.deep_copy_table(getmetatable(orig)))
else -- number, string, boolean, etc
copy = orig
end
return copy
end --deep_copy_table
-- Credit to http://stackoverflow.com/a/1283608/2644759
-- cc-by-sa 3.0
function p.tableMerge (t1, t2)
for k,v in pairs(t2) do
if type(v) == "table" then
if type(t1[k] or false) == "table" then
p.tableMerge(t1[k] or {}, t2[k] or {})
elseif ((v ~= nil) and (t1[k] == nil)) or p.HasValue(v) then --old version ...else t1[k] = v end
t1[k] = v
end
elseif ((v ~= nil) and (t1[k] == nil)) or p.HasValue(v) then --old version ...else t1[k] = v end
t1[k] = v
end
end
return t1
end --tableMerge
local wiki_langcode = mw.language.getContentLanguage().code
function p.get_lang (langcode)
--form Module:Wikidades
if mw.language.isKnownLanguageTag(langcode or '') == false then
if not mw.title.getCurrentTitle().isContentPage then
local cframe = mw.getCurrentFrame()
langcode = cframe:preprocess('{{int:lang}}')
end
if mw.language.isKnownLanguageTag(langcode or '') == false then
langcode = wiki_langcode
end
end
return langcode
end --get_lang
p.lang_to_use = p.get_lang ()
function p.I18nName (ModName)
local i18n_suffix0 = "/i18n"
local i18n_suffix = ''
if p.lang_to_use ~= wiki_langcode then
i18n_suffix = i18n_suffix0..'/'..p.lang_to_use
else
i18n_suffix = i18n_suffix0
end
local FN = "Module:"..ModName
local title = mw.title.new (FN..i18n_suffix)
if title.exists then
return FN..i18n_suffix
else
FN = FN..i18n_suffix0
title = mw.title.new (FN)
if title.exists then
return FN
else
error (string.format('Not found "%s"',FN)) -- Translation not required
end
end
end --I18nName
function p.loadI18n (ModName, DefTable)
local FN = p.I18nName (ModName)
return p.tableMerge(DefTable, require(FN).i18n)
end --loadI18n
---
function p.I18nStrParams (S, ...)
local result = mw.message.newRawMessage (S, ...)
return result:plain()
end
function p.TrimWdTab (tab)
for k, i in ipairs(tab) do
tab[k] = mw.text.trim (i)
end
return tab
end --TrimWdTab
function p.I18nParamsTab (Wds, MaxTrans)
local tab = mw.text.split (Wds, '|')
if (MaxTrans ~= nil) and (#tab > MaxTrans) then
error (string.format('Found %s translations for "%s"',#tab,S)) -- Translation not required
end
return p.TrimWdTab (tab)
end --I18nParamsTab
function p.I18nParamsTabCS (Wds, CaseSensitive)
CaseSensitive = ((CaseSensitive ~= nil) and (CaseSensitive == true)) or true
if not CaseSensitive then
Wds = string.lower (Wds)
end
tab = mw.text.split (Wds, '|')
return p.TrimWdTab (tab)
end --I18nParamsTabCS
function p.SFoundInWdTab (WdTable, val, CaseSensitive, S)
if (S == nil) or (S == '') then
error('Not parameters trying to find "'..val..'"') --It doesn't require translation, only for degug
end
local Arr = p.I18nParamsTabCS (WdTable[S], CaseSensitive)
if not CaseSensitive then
val = string.lower (val)
end
for _, W in ipairs(Arr) do
if W == val then
return true
end
end
return false
end --SFoundInWdTab
function p.IdxFromWdTab (WdTable, val, CaseSensitive, ...)
local Arr = unpack(arg)
if Arr == nil then
error('Not parameters trying to find "'..val..'"') --It doesn't require translation, only for degug
end
local Idx = 0
for I, W in ipairs(Arr) do
if p.SFoundInWdTab (WdTable, val, CaseSensitive, W) then
Idx = I
break
end
end
return Idx
end --IdxFromWdTab
function p.JoinI18nTables (tabs)
local res = {}
for _, v in ipairs(tabs) do
for _, vv in pairs(v) do
table.insert (res, vv)
end
end
return res
end --JoinTables
----------
i18n = p.loadI18n (I18n, i18n)
local function I18nStr (S, ...)
return p.I18nStrParams (i18n[S], ...)
end
function p.i18n_vals (frame)
local args = p.GetArgs (frame)
local res = i18n[p.RStr_Par(args,1)]
if res == nil then
error ('Invalid word')
else
return res
end
end --i18n_vals
----------
p.Error = {
handle = false,
yes = false,
msg = '',
samesize = false
}
function p.MsgError (S)
if S == nil then
if p.Error.samesize then
return '<span style="color:red;font-weight:bold">'..p.Error.msg..'</span>'
else
return '<strong class="error">'..p.Error.msg..'</strong>'
end
else
if p.Error.handle then
p.Error.msg = S
p.Error.yes = true
else
error (S, 0)
end
end
end--MsgError
function p.GetAndClearError ()
local E = p.Error.msg
p.Error.msg = ''
p.Error.yes = false
return E
end --GetAndClearError
function p.TableSize (tab)
Count = 0
for _, v in pairs(tab) do
Count = Count + 1
end
return Count
end --TableSize
function p.TableWithItems (tab)
if #tab > 0 then
return true
else
for _, v in pairs(tab) do
return true
end
return false
end
end --TableWithItems
function p.GetArgs (frame, HandleError, SameSize)
local origArgs
if frame == mw.getCurrentFrame() then
-- We're being called via #invoke. If the invoking template passed any parameters,
-- use them. Otherwise, use the parameters that were passed into the template.
origArgs = frame:getParent().args
for _, v in pairs( frame.args ) do
origArgs = frame.args
break
end
else
-- We're being called from another module or from the debug console, so assume
-- the parameters are passed in directly.
origArgs = frame
end
NArgs = p.TableSize (origArgs)
if (HandleError ~= nil) and (HandleError == true) then
p.Error.handle = true
if (SameSize ~= nil) and (SameSize == true) then
p.Error.samesize = true
end
end
if p.Error.handle and (NArgs == 0) then
p.MsgError ('')
end
return origArgs, NArgs
end --GetArgs
function p.GetArgsT (frame, HandleError, SameSize)
--Get paramenters,num from template that call to module (returned 1st,2nd) and from module (returned 3rd,4th)
local origArgs, NArgs = p.GetArgs (frame, HandleError, SameSize)
pargs = frame:getParent().args
NPArgs = p.TableSize(pargs)
if NPArgs == 0 then
return pargs, NPArgs, origArgs, NArgs
else
return origArgs, NArgs, pargs, NPArgs
end
end --GetArgsT
function p.GetArgsTMerge (frame, HandleError, SameSize)
local arg1, NArg1, arg2, NArg2 = p.GetArgsT (frame, HandleError, SameSize)
local args = {}
for k, val in pairs(arg1) do
args[k] = val
end
for k, val in pairs(arg2) do
args[k] = val
end
return args
end --GetArgsTMerge
p.ParaSep = '/'
function p.ConcatParams (tab)
return '"'..table.concat(tab,p.ParaSep)..'"'
end
local function ParamErrorS (ParId, S)
if ParId == nil then
error ('Not assigned ParId') --Not require translation, only debug
elseif ParId ~= '' then
local SParaId = ''
if type(ParId)=='table' then
SParaId = p.ConcatParams (ParId)
else
if type(ParId)=='number' then
ParId = '#'..ParId
end
SParaId = ParId
end
S = SParaId..' = '..S
end
p.MsgError (S)
end--ParamErrorS
local function ParamError (ParId, RS, Value)
if Value == '' then
Value = '""'
end
local S = I18nStr (RS, tostring(Value))
ParamErrorS (ParId, S)
end--ParamError
----------
local function GetArgsPass (args)
local ArgsPass = {}
for k, v in pairs(args) do
if type(k) == 'string' then
table.insert (ArgsPass, k)
end
end
return ArgsPass
end --GetArgsPass
function p.ErrNotFoundArgName (v)
p.MsgError (I18nStr (RS.NotFoundArgName, v))
end
function p.CheckParams (args, UsualArgs)
if p.Error.yes then return end
local ArgsPass = GetArgsPass (args)
local UsualArgsC = p.deep_copy_table (UsualArgs)
for _, v in ipairs(ArgsPass) do
local found = false
for kk, vv in pairs(UsualArgsC) do
if type(vv) == 'table' then
for j, w in ipairs(vv) do
if v == w then
found = true
UsualArgsC[kk][j] = nil
break
end
end
else
if v == vv then
found = true
UsualArgsC[kk] = nil
end
end
if found then
break
end
end
if not found then
p.ErrNotFoundArgName (v)
break
end
end
end --CheckParams
p.HasChild = 'HasChild'
function p.CheckParamsM (args, UsualArgs, OtherArgs, ArgNamesIn1)
--[[ Warning!: UsualArgs is a table of table or parameters,
e.g.{args_main_module, args_shared_module1, args_shared_module2} or
{args_main_module}
In ArgNamesIn1 mode, each parameter has the name/s and type: e.g.
["key"] = {"Arg_name", "i+"} or
["key"] = {{"Arg_name","arg_name"} "i+"}
in this case "i+" indicates a positive integer.
--]]
if p.Error.yes then return end
if p.Error.handle then
unknown_param = {}
end
local ArgsPass = GetArgsPass (args)
local flags_dupli_args = {}
local flags_dupli_args_s = {}
local dupli_args = {}
local key = ''
local UsualArgsC = p.deep_copy_table (UsualArgs)
for _, v in ipairs(ArgsPass) do
local found = false
for kk, vv in ipairs(UsualArgsC) do
if vv[p.HasChild] == true then
for j, w in pairs(vv) do
if j ~= p.HasChild then
for jj, ww in pairs(w) do
if ArgNamesIn1 then
ww = ww[1] --skip type
end
if type(ww) == 'table' then
for jjj, www in ipairs(ww) do
if v == www then
found = true
key = jj
break
end
end
else
if v == ww then
key = jj
found = true
end
end
if found then
break
end
end
end
if found then
break
end
end
else
for j, w in pairs(vv) do
if ArgNamesIn1 then
w = w[1] --skip type
end
if type(w) == 'table' then
for jj, ww in ipairs(w) do
if v == ww then
key = j
found = true
break
end
end
else
if v == w then
key = j
found = true
end
end
if found then
break
end
end
end
if found then
break
end
end
if found then
if flags_dupli_args[key] then
table.insert (dupli_args, key..' ('..flags_dupli_args_s[key]..'-'..v..')')
else
flags_dupli_args[key] = true
flags_dupli_args_s[key] = v
end
end
if (not found) and (OtherArgs ~= nil) then
if type(OtherArgs) == 'table' then
for _, vv in ipairs(OtherArgs) do
if v == vv then
found = true
break
end
end
else
found = v == vv
end
end
if not found then
p.ErrNotFoundArgName (v)
if p.Error.handle then
table.insert (unknown_param, p.GetAndClearError())
else
break
end
end
end
if p.Error.handle and ((#unknown_param > 0) or (#dupli_args > 0)) then
return unknown_param, dupli_args
end
end --CheckParamsM
----------
local function prepNum (N)
return mw.getContentLanguage():formatNum (N)
end
function p.CheckNum (N, ParId, LimInf, LimSup)
if (p.Error.yes) or (not N) then return end
if ((LimInf ~= nil) and (N < LimInf)) and ((LimSup ~= nil) and (N > LimSup)) then
ParamErrorS (ParId, I18nStr (RS.NIsNotInRange, prepNum(N), prepNum(LimInf), prepNum(LimSup)))
elseif (LimInf ~= nil) and (N < LimInf) then
ParamErrorS (ParId, I18nStr (RS.NIsLessThan, prepNum(N), prepNum(LimInf)))
elseif (LimSup ~= nil) and (N > LimSup) then
ParamErrorS (ParId, I18nStr (RS.NIsGreaterThan, prepNum(N), prepNum(LimSup)))
end
end --p.CheckNum
function p.CheckNumIsInt (N, ParId, LimInf, LimSup)
if p.Error.yes then return end
if N == math.floor(N) then
p.CheckNum (N, ParId, LimInf, LimSup)
else
ParamError (ParId, RS.NIsNotInt, prepNum(N))
end
end --CheckNumIsInt
function p.CheckNumIsPos (N, ParId, LimInf, LimSup)
if p.Error.yes then return end
if N > 0 then
p.CheckNum (N, ParId, LimInf, LimSup)
else
ParamError (ParId, RS.NIsNotPosNumber, N)
end
end --CheckNumIsPos
function p.CheckNumIsZeroOrPos (N, ParId, LimSup)
if p.Error.yes then return end
if N >= 0 then
p.CheckNum (N, ParId, 0, LimSup)
else
ParamError (ParId, RS.NIsNotZeroOrPosNumber, N)
end
end --CheckNumIsZeroOrPos
-----
function p.CheckSIsNum (S, ParId, LimInf, LimSup)
if p.Error.yes then return end
local N = tonumber(S)
if not N then
ParamError (ParId, RS.SIsNotNumber, S)
else
p.CheckNum (N, ParId, LimInf, LimSup)
end
end --CheckSIsNum
function p.CheckSIsInt (S, Where, LimInf, LimSup)
if p.Error.yes then return end
p.CheckSIsNum (S, Where, LimInf, LimSup)
if p.Error.yes then return end
p.CheckNumIsInt (tonumber(S), Where)
end
function p.CheckSIsPosInt (S, ParId, LimInf, LimSup)
if p.Error.yes then return end
p.CheckSIsInt (S, ParId, LimInf, LimSup)
if p.Error.yes then return end
p.CheckNumIsPos (tonumber(S), ParId)
end
function p.CheckSIsZeroOrPosInt (S, ParId, LimSup)
if p.Error.yes then return end
p.CheckSIsInt (S, ParId, 0, LimSup)
if p.Error.yes then return end
p.CheckNumIsZeroOrPos (tonumber(S), ParId)
end
function p.NotAssignedValue (ParId)
ParamErrorS (ParId, I18nStr (RS.SIsNotAssigned))
end
----------
p.OKEmptyVal = true
function p.Str_Par (Args, ParId, Default)
if p.Error.yes then return end
local S = nil
if type(ParId) == 'table' then
for _, W in ipairs(ParId) do
S = Args[W]
if S ~= nil then
break
end
end
else
S = Args[ParId]
end
if S == nil then
if Default ~= nil then
S = Default
end
else
S = mw.text.trim (S)
if S == '' then
if Default ~= nil then
S = Default
elseif not p.OKEmptyVal then
S = nil
end
end
end
return S
end --Str_Par
function p.RStr_Par (Args, ParId, OKEmpty)
if p.Error.yes then return end
local S = p.Str_Par (Args, ParId)
if (S == nil) or ((S == '') and ((OKEmpty == nil) or (not OKEmpty))) then
p.NotAssignedValue (ParId)
else
return S
end
end --RStr_Par
function p.Char_Par (Args, ParId, Pattern, Default)
if p.Error.yes then return end
local Char = p.Str_Par (Args, ParId, Default)
if p.Error.yes then return end
if Char ~= nil then
local Valid = ((Default ~= nil) and (Char == Default)) or (string.len(Char) == 1) and (string.find(Pattern,Char) ~= nil)
if not Valid then
ParamErrorS (ParId, I18nStr (RS.CharNotFoundInPattern, Char, Pattern))
end
end
return Char
end --Char_Par
function p.RChar_Par (Args, ParId, Pattern)
if p.Error.yes then return end
local Char = p.Char_Par (Args, ParId, Pattern)
if p.Error.yes then return end
if Char == nil then
p.NotAssignedValue (ParId)
else
return Char
end
end --RChar_Par
function p.NulOrWhitespace_Par (Args, ParId)
if p.Error.yes then return end
local S = p.Str_Par (Args, ParId)
if p.Error.yes then return end
return (S == nil) or (S == '')
end
local function PerhapsLow (CaseSens, Wd)
if CaseSens then
return Wd
else
return string.lower(Wd)
end
end --PerhapsLow
function p.StrChkTab_Par0 (ParId, S, Tab, CaseSens, Default)
if (S ~= nil) and (S ~= Default) then
local SIni = S
S = PerhapsLow(CaseSens,S)
local found = false
for _, W in ipairs(Tab) do
if S == PerhapsLow(CaseSens,W) then
S = W
found = true
break
end
end
if not found then
ParamErrorS (ParId, I18nStr (RS.SNotFoundInTab, SIni, table.concat(Tab,', ')))
S = nil
end
end
return S
end --StrChkTab_Par0
function p.StrChkTab_Par (Args, ParId, Tab, CaseSens, Default)
if p.Error.yes then return end
local S = p.Str_Par (Args, ParId, Default)
if p.Error.yes then return end
return p.StrChkTab_Par0 (ParId, S, Tab, CaseSens, Default)
end --StrChkTab_Par
function p.RStrChkTab_Par (Args, ParId, Tab, CaseSens)
if p.Error.yes then return end
local S = p.StrChkTab_Par (Args, ParId, Tab)
if p.Error.yes then return end
if S == nil then
p.NotAssignedValue (ParId)
else
return S
end
end --RStrChkTab_Par
function p.StrIdxChkTab_Par (Args, ParId, Tab, CaseSens, Default)
if p.Error.yes then return end
local S = p.Str_Par (Args, ParId, Default)
if p.Error.yes then return end
if (S ~= nil) and (S ~= Default) then
local SIni = S
S = PerhapsLow(CaseSens,S)
local found = false
for I, W in ipairs(Tab) do
if S == PerhapsLow(CaseSens,W) then
S = I
found = true
break
end
end
if not found then
ParamErrorS (ParId, I18nStr (RS.SNotFoundInTab, SIni, table.concat(Tab,', ')))
S = nil
end
end
return S
end --StrIdxChkTab_Par
function p.RStrIdxChkTab_Par (Args, ParId, Tab, CaseSens)
if p.Error.yes then return end
local S = p.StrIdxChkTab_Par (Args, ParId, Tab)
if p.Error.yes then return end
if S == nil then
p.NotAssignedValue (ParId)
else
return S
end
end --RStrIdxChkTab_Par
--Used in parameters to force an integer, number and others to return "NONE" (parameter to non-use)
p.AcceptNone = false
p.None = "NONE"
local function IsNone (S)
return p.AcceptNone and (S == p.None)
end
function p.Num_Par (Args, ParId, Default, LimInf, LimSup)
if p.Error.yes then return end
local N = p.Str_Par (Args, ParId)
if p.Error.yes then return end
if IsNone(N) then return p.None end
if N == nil then
if Default ~= nil then
N = Default
end
return N, true
else
p.CheckSIsNum (N, ParId, LimInf, LimSup)
if p.Error.yes then return end
return tonumber(N), false
end
end --Num_Par
function p.RNum_Par (Args, ParId, LimInf, LimSup)
if p.Error.yes then return end
local N = p.Num_Par (Args, ParId, nil, LimInf, LimSup)
if p.Error.yes then return end
if N == nil then
p.NotAssignedValue (ParId)
else
return N, false
end
end --RNum_Par
function p.PosNum_Par (Args, ParId, Default, LimInf, LimSup)
if p.Error.yes then return end
local N, IsDefault = p.Num_Par (Args, ParId, Default, LimInf, LimSup)
if IsNone(N) then return p.None end
if p.Error.yes then return end
if not IsDefault then
p.CheckNumIsPos (N, ParId)
if p.Error.yes then return end
end
return N
end --PosNum_Par
function p.RPosNum_Par (Args, ParId, LimInf, LimSup)
if p.Error.yes then return end
local N = p.PosNum_Par (Args, ParId, nil, LimInf, LimSup)
if p.Error.yes then return end
if N == nil then
p.NotAssignedValue (ParId)
else
return N
end
end --RNum_Par
function p.ZeroOrPosNum_Par (Args, ParId, Default, LimSup)
if p.Error.yes then return end
local N, IsDefault = p.Num_Par (Args, ParId, Default, 0, LimSup)
if IsNone(N) then return p.None end
if p.Error.yes then return end
if not IsDefault then
p.CheckNumIsZeroOrPos (N, ParId)
if p.Error.yes then return end
end
return N
end --ZeroOrPosNum_Par
function p.RZeroOrPosNum_Par (Args, ParId, LimSup)
if p.Error.yes then return end
local N = p.ZeroOrPosNum_Par (Args, ParId, nil, LimSup)
if p.Error.yes then return end
if N == nil then
p.NotAssignedValue (ParId)
else
return N
end
end --RZeroOrPosNum_Par
function p.Int_Par (Args, ParId, Default, LimInf, LimSup)
N, IsDefault = p.Num_Par (Args, ParId, Default, LimInf, LimSup)
if IsNone(N) then return p.None end
if p.Error.yes then return end
if not IsDefault then
p.CheckNumIsInt (N, ParId)
if p.Error.yes then return end
end
return N
end --Int_Par
function p.RInt_Par (Args, ParId, LimInf, LimSup)
if p.Error.yes then return end
local N = p.Int_Par (Args, ParId, nil, LimInf, LimSup)
if p.Error.yes then return end
if N == nil then
p.NotAssignedValue (ParId)
else
return N, true
end
end --RInt_Par
function p.PosInt_Par (Args, ParId, Default, LimInf, LimSup)
if p.Error.yes then return end
local N = p.Int_Par (Args, ParId, Default, LimInf, LimSup)
if IsNone(N) then return p.None end
if p.Error.yes then return end
if N ~= nil then
p.CheckNumIsPos (N, ParId)
if p.Error.yes then return end
end
return N
end --PosInt_Par
function p.RPosInt_Par (Args, ParId, LimInf, LimSup)
if p.Error.yes then return end
local N = p.PosInt_Par (Args, ParId, nil, LimInf, LimSup)
if p.Error.yes then return end
if N == nil then
p.NotAssignedValue (ParId)
else
return N, false
end
end --RPosInt_Par
function p.ZeroOrPosInt_Par (Args, ParId, Default, LimSup)
if p.Error.yes then return end
local N = p.Int_Par (Args, ParId, Default, 0, LimSup)
if IsNone(N) then return p.None end
if p.Error.yes then return end
if N ~= nil then
p.CheckNumIsZeroOrPos (N, ParId)
if p.Error.yes then return end
end
return N
end --ZeroOrPosInt_Par
function p.RZeroOrPosInt_Par (Args, ParId, LimSup)
if p.Error.yes then return end
local N = p.ZeroOrPosInt_Par (Args, ParId, nil, LimSup)
if p.Error.yes then return end
if N == nil then
p.NotAssignedValue (ParId)
else
return N, true
end
end --RZeroOrPosInt_Par
---
local function PossibleValues (tab)
local S = ''
for _, W in ipairs(tab) do
if S ~='' then
S = S..', '
end
local tab = {}
tab2 = p.I18nParamsTabCS (i18n[W])
S = S..table.concat (tab2, p.ParaSep)
end
return I18nStr (RS.PossibleValues, S)
end --PossibleValues
---
function p.CheckSize (CurCol, width) --used in XCols
local val = string.match (width, '%d[%d.,]*')
if val == nil then
ParamErrorS (CurCol, I18nStr (RS.SizeWithoutNumber))
else
local unit = string.sub (width, #val+1)
if unit == '' then
ParamErrorS (CurCol, I18nStr (RS.SizeUnitRequired))
elseif (unit ~= '%') and (unit ~= 'em') and (unit ~= 'px') then
ParamErrorS (CurCol, I18nStr (RS.InvalSizeUnit, unit))
end
end
end --CheckSize
function p.Size_Par (Args, ParId, WithPerc, limits, Default)
if p.Error.yes then return end
local width = p.Str_Par (Args, ParId, Default)
if p.Error.yes then return end
if p.HasValue (width) then
local val = string.match (width, '%d[%d.,]*')
if val == nil then
ParamErrorS (ParId, I18nStr (RS.SizeWithoutNumber))
else
local unit = string.sub (width, #val+1)
if unit == '' then
ParamErrorS (ParId, I18nStr (RS.SizeUnitRequired))
elseif (not WithPerc) and (unit == '%') then
ParamErrorS (ParId, I18nStr (RS.InvalSizeUnit, unit))
elseif (unit ~= '%') and (unit ~= 'em') and (unit ~= 'px') then
ParamErrorS (ParId, I18nStr (RS.InvalSizeUnit, unit))
elseif limits ~= nil then
checked = false
val = tonumber (val)
function Check (sel_lim, sel_unit)
if (not checked) and (sel_lim ~= nil) and (unit == sel_unit) then
if ((sel_lim[1] ~= nil) and (val < sel_lim[1])) or ((sel_lim[2] ~= nil) and (val > sel_lim[2])) then
ParamErrorS (ParId, I18nStr (RS.NIsNotInRange, width, sel_lim[1]..sel_unit, sel_lim[2]..sel_unit))
end
checked = true
end
end
Check (limits['em'], 'em')
Check (limits['px'], 'px')
if WithPerc then
Check (limits['perc'], '%')
end
end
end
end
return width
end --Size_Par
function p.RSize_Par (Args, ParId, WithPerc, limits)
if p.Error.yes then return end
local width = p.Size_Par (Args, ParId, WithPerc, limits)
if p.Error.yes then return end
if width == nil then
p.NotAssignedValue (ParId)
else
return width
end
end --RSize_Par
p.Colors = {
-- Pink colors
["pink"] = 'FFC0CB', -- Pink
["lightpink"] = 'FFB6C1', -- LightPink
["hotpink"] = 'FF69B4', -- HotPink
["deeppink"] = 'FF1493', -- DeepPink
["palevioletred"] = 'DB7093', -- PaleVioletRed
["mediumvioletred"] = 'C71585', -- MediumVioletRed
-- Red colors
["lightsalmon"] = 'FFA07A', -- LightSalmon
["salmon"] = 'FA8072', -- Salmon
["darksalmon"] = 'E9967A', -- DarkSalmon
["lightcoral"] = 'F08080', -- LightCoral
["indianred"] = 'CD5C5C', -- IndianRed
["crimson"] = 'DC143C', -- Crimson
["firebrick"] = 'B22222', -- Firebrick
["darkred"] = '8B0000', -- DarkRed
["red"] = 'FF0000', -- Red
-- Orange colors
["orangered"] = 'FF4500', -- OrangeRed
["tomato"] = 'FF6347', -- Tomato
["coral"] = 'FF7F50', -- Coral
["darkorange"] = 'FF8C00', -- DarkOrange
["orange"] = 'FFA500', -- Orange
-- Yellow colors
["yellow"] = 'FFFF00', -- Yellow
["lightyellow"] = 'FFFFE0', -- LightYellow
["lemonchiffon"] = 'FFFACD', -- LemonChiffon
["lightgoldenrodyellow"] = 'FAFAD2', -- LightGoldenrodYellow
["papayawhip"] = 'FFEFD5', -- PapayaWhip
["moccasin"] = 'FFE4B5', -- Moccasin
["peachpuff"] = 'FFDAB9', -- PeachPuff
["palegoldenrod"] = 'EEE8AA', -- PaleGoldenrod
["khaki"] = 'F0E68C', -- Khaki
["darkkhaki"] = 'BDB76B', -- DarkKhaki
["gold"] = 'FFD700', -- Gold
-- Brown colors
["cornsilk"] = 'FFF8DC', -- Cornsilk
["blanchedalmond"] = 'FFEBCD', -- BlanchedAlmond
["bisque"] = 'FFE4C4', -- Bisque
["navajowhite"] = 'FFDEAD', -- NavajoWhite
["wheat"] = 'F5DEB3', -- Wheat
["burlywood"] = 'DEB887', -- Burlywood
["tan"] = 'D2B48C', -- Tan
["rosybrown"] = 'BC8F8F', -- RosyBrown
["sandybrown"] = 'F4A460', -- SandyBrown
["goldenrod"] = 'DAA520', -- Goldenrod
["darkgoldenrod"] = 'B8860B', -- DarkGoldenrod
["peru"] = 'CD853F', -- Peru
["chocolate"] = 'D2691E', -- Chocolate
["saddlebrown"] = '8B4513', -- SaddleBrown
["sienna"] = 'A0522D', -- Sienna
["brown"] = 'A52A2A', -- Brown
["maroon"] = '800000', -- Maroon
-- Green colors
["darkolivegreen"] = '556B2F', -- DarkOliveGreen
["olive"] = '808000', -- Olive
["olivedrab"] = '6B8E23', -- OliveDrab
["yellowgreen"] = '9ACD32', -- YellowGreen
["limegreen"] = '32CD32', -- LimeGreen
["lime"] = '00FF00', -- Lime
["lawngreen"] = '7CFC00', -- LawnGreen
["chartreuse"] = '7FFF00', -- Chartreuse
["greenyellow"] = 'ADFF2F', -- GreenYellow
["springgreen"] = '00FF7F', -- SpringGreen
["mediumspringgreen"] = '00FA9A', -- MediumSpringGreen
["lightgreen"] = '90EE90', -- LightGreen
["palegreen"] = '98FB98', -- PaleGreen
["darkseagreen"] = '8FBC8F', -- DarkSeaGreen
["mediumaquamarine"] = '66CDAA', -- MediumAquamarine
["mediumseagreen"] = '3CB371', -- MediumSeaGreen
["seagreen"] = '2E8B57', -- SeaGreen
["forestgreen"] = '228B22', -- ForestGreen
["green"] = '008000', -- Green
["darkgreen"] = '006400', -- DarkGreen
-- Cyan colors
["aqua"] = '00FFFF', -- Aqua
["cyan"] = '00FFFF', -- Cyan
["lightcyan"] = 'E0FFFF', -- LightCyan
["paleturquoise"] = 'AFEEEE', -- PaleTurquoise
["aquamarine"] = '7FFFD4', -- Aquamarine
["turquoise"] = '40E0D0', -- Turquoise
["mediumturquoise"] = '48D1CC', -- MediumTurquoise
["darkturquoise"] = '00CED1', -- DarkTurquoise
["lightseagreen"] = '20B2AA', -- LightSeaGreen
["cadetblue"] = '5F9EA0', -- CadetBlue
["darkcyan"] = '008B8B', -- DarkCyan
["teal"] = '008080', -- Teal
-- Blue colors
["lightsteelblue"] = 'B0C4DE', -- LightSteelBlue
["powderblue"] = 'B0E0E6', -- PowderBlue
["lightblue"] = 'ADD8E6', -- LightBlue
["skyblue"] = '87CEEB', -- SkyBlue
["lightskyblue"] = '87CEFA', -- LightSkyBlue
["deepskyblue"] = '00BFFF', -- DeepSkyBlue
["dodgerblue"] = '1E90FF', -- DodgerBlue
["cornflowerblue"] = '6495ED', -- CornflowerBlue
["steelblue"] = '4682B4', -- SteelBlue
["royalblue"] = '4169E1', -- RoyalBlue
["blue"] = '0000FF', -- Blue
["mediumblue"] = '0000CD', -- MediumBlue
["darkblue"] = '00008B', -- DarkBlue
["navy"] = '000080', -- Navy
["midnightblue"] = '191970', -- MidnightBlue
-- Purple, violet, and magenta colors
["lavender"] = 'E6E6FA', -- Lavender
["thistle"] = 'D8BFD8', -- Thistle
["plum"] = 'DDA0DD', -- Plum
["violet"] = 'EE82EE', -- Violet
["orchid"] = 'DA70D6', -- Orchid
["fuchsia"] = 'FF00FF', -- Fuchsia
["magenta"] = 'FF00FF', -- Magenta
["mediumorchid"] = 'BA55D3', -- MediumOrchid
["mediumpurple"] = '9370DB', -- MediumPurple
["blueviolet"] = '8A2BE2', -- BlueViolet
["darkviolet"] = '9400D3', -- DarkViolet
["darkorchid"] = '9932CC', -- DarkOrchid
["darkmagenta"] = '8B008B', -- DarkMagenta
["purple"] = '800080', -- Purple
["indigo"] = '4B0082', -- Indigo
["darkslateblue"] = '483D8B', -- DarkSlateBlue
["slateblue"] = '6A5ACD', -- SlateBlue
["mediumslateblue"] = '7B68EE', -- MediumSlateBlue
-- White colors
["white"] = 'FFFFFF', -- White
["snow"] = 'FFFAFA', -- Snow
["honeydew"] = 'F0FFF0', -- Honeydew
["mintcream"] = 'F5FFFA', -- MintCream
["azure"] = 'F0FFFF', -- Azure
["aliceblue"] = 'F0F8FF', -- AliceBlue
["ghostwhite"] = 'F8F8FF', -- GhostWhite
["whitesmoke"] = 'F5F5F5', -- WhiteSmoke
["seashell"] = 'FFF5EE', -- Seashell
["beige"] = 'F5F5DC', -- Beige
["oldlace"] = 'FDF5E6', -- OldLace
["floralwhite"] = 'FFFAF0', -- FloralWhite
["ivory"] = 'FFFFF0', -- Ivory
["antiquewhite"] = 'FAEBD7', -- AntiqueWhite
["linen"] = 'FAF0E6', -- Linen
["lavenderblush"] = 'FFF0F5', -- LavenderBlush
["mistyrose"] = 'FFE4E1', -- MistyRose
-- Gray and black colors
["gainsboro"] = 'DCDCDC', -- Gainsboro
["lightgray"] = 'D3D3D3', -- LightGray
["silver"] = 'C0C0C0', -- Silver
["darkgray"] = 'A9A9A9', -- DarkGray
["gray"] = '808080', -- Gray
["dimgray"] = '696969', -- DimGray
["lightslategray"] = '778899', -- LightSlateGray
["slategray"] = '708090', -- SlateGray
["darkslategray"] = '2F4F4F', -- DarkSlateGray
["black"] = '000000', -- Black
}
function p.ColorToHex (frame)
local args = p.GetArgs (frame)
return p.RColor_Par (args, 1)
end
local function GetRValue (rgb)
-- Red color
return tonumber (string.sub(rgb,1,2), 16)
end
local function GetGValue(rgb)
-- Green color
return tonumber (string.sub(rgb,3,4), 16)
end
local function GetBValue(rgb)
-- BLue color
return tonumber (string.sub(rgb,5,6), 16)
end
function p.CheckSIsColor (S, ParId, Default)
-- Returns if is valid and the color in format NNNNNN i.e.
-- for S == 'Green' returns true,'008000'
-- for S == '#008000' returns true,'008000'
function SixCharsFromCol (Col)
if Col == nil then
return nil
else
function NumColor (Col)
if string.len (Col) ~= 6 then
ParamError (ParId, RS.InvalColorLength, Col)
end
if tonumber ('0x'..Col) == nil then
ParamError (ParId, RS.InvalColorChar, Col)
end
end
if string.sub (Col, 1, 5) == '#' then
Col = string.sub (Col, 6)
NumColor (Col)
elseif string.sub (Col, 1, 1) == '#' then
Col = string.sub (Col, 2)
NumColor (Col)
else
local ColI = Col
local rgbn = string.lower (Col)
Col = p.Colors[rgbn]
if Col == nil then
ParamError (ParId, RS.InvalColorName, ColI)
end
end
if p.Error.yes then
return nil
else
return Col
end
end
end -- SixCharsFromCol
if p.Error.yes then return end
if S == nil then
S = Default
return SixCharsFromCol (S)
end
if S == nil then
return nil
else
return SixCharsFromCol (S)
end
end --CheckSIsColor
function p.Color_Par (Args, ParId, Default)
if p.Error.yes then return end
local rgb = p.Str_Par (Args, ParId)
if p.Error.yes then return end
return p.CheckSIsColor (rgb, ParId, Default)
end --Color_Par
function p.RColor_Par (Args, ParId, Default)
if p.Error.yes then return end
local rgb = p.RStr_Par (Args, ParId)
if p.Error.yes then return end
return p.CheckSIsColor (rgb, ParId)
end --Color_Par
---
function p.HAlign_Par (Args, ParId, Default)
local HAlign = {
RS.left,
RS.right,
RS.center,
}
if p.Error.yes then return end
local align = p.Str_Par (Args, ParId)
if p.Error.yes then return end
if (align == nil) or (align == '') then
return Default
else
local Idx = p.IdxFromWdTab (i18n, align, true, HAlign)
if Idx == 0 then
ParamErrorS (ParId, I18nStr (RS.InvalAlign,align)..'. '..PossibleValues(HAlign))
else
return HAlign[Idx]
end
end
end --HAlign_Par
function p.RHAlign_Par (Args, ParId)
if p.Error.yes then return end
local align = p.HAlign_Par (Args, ParId)
if p.Error.yes then return end
if align == nil then
p.NotAssignedValue (ParId)
else
return align
end
end --RHAlign_Par
---
function p.VAlign_Par (Args, ParId, Default)
local VAlign = {
RS.top,
RS.bottom,
RS.center,
}
if p.Error.yes then return end
local align = p.Str_Par (Args, ParId)
if p.Error.yes then return end
if (align == nil) or (align == '') then
return Default
else
local Idx = p.IdxFromWdTab (i18n, align, true, VAlign)
if Idx == 0 then
ParamErrorS (ParId, I18nStr (RS.InvalAlign,align)..'. '..PossibleValues(VAlign))
else
return VAlign[Idx]
end
end
end --VAlign_Par
function p.RVAlign_Par (Args, ParId)
if p.Error.yes then return end
local align = p.VAlign_Par (Args, ParId)
if p.Error.yes then return end
if align == nil then
p.NotAssignedValue (ParId)
else
return align
end
end --RVAlign_Par
---
function p.Bool_Par (Args, ParId, Default)
local yesno = {
RS.Yes,
RS.No,
}
if p.Error.yes then return end
local B = p.Str_Par (Args, ParId)
if IsNone(N) then return p.None end
if p.Error.yes then return end
if (B == nil) or (B == '') then
return Default
else
local Idx = p.IdxFromWdTab (i18n, B, true, yesno)
if Idx == 0 then
ParamErrorS (ParId, I18nStr (RS.InvalBool,B)..'. '..PossibleValues(yesno))
elseif Idx == 1 then
return true
elseif Idx == 2 then
return false
end
end
end --Bool_Par
function p.RBool_Par (Args, ParId)
if p.Error.yes then return end
local B = p.Bool_Par (Args, ParId)
if p.Error.yes then return end
if B == nil then
p.NotAssignedValue (ParId)
else
return B
end
end --RBool_Par
---
function SFoundInArr (val, CaseSens, ParId)
found = false
if type(ParId) == 'table' then
for _, W in ipairs(ParId) do
if val == PerhapsLow(CaseSens, W) then
found = true
break
end
end
else
if val == PerhapsLow(CaseSens, ParId) then
found = true
end
end
return found
end --SFoundInArr
local function StrIdxChkTab0 (val, CaseSens, Default, ...)
if p.Error.yes then return end
if arg == nil then
error('Not parameters trying to find "'..W..'"') --It doesn't require translation, only for degug
end
local Idx = 0
if not p.Error.yes then
if not CaseSens then
val = string.lower(val)
end
local tab = unpack(arg)
for I, W in ipairs(tab) do
if SFoundInArr (val, CaseSens, W) then
Idx = I
break
end
end
if (Idx == 0) and (Default ~= nil) then
Idx = Default
end
end
if p.Error.yes then
return p.MsgError()
else
return Idx
end
end --StrIdxChkTab0
function p.StrIdxChkTab (Args, ParId, CaseSens, Default, ...)
if p.Error.yes then return end
local W = p.Str_Par (Args, ParId, Default)
local Idx = StrIdxChkTab0 (W, CaseSens, Default, arg)
if p.Error.yes then
return p.MsgError()
else
return Idx
end
end--StrIdxChkTab
function p.RStrIdxChkTab (Args, ParId, CaseSens, ...)
if p.Error.yes then return end
local W = p.RStr_Par (Args, ParId)
local Idx = StrIdxChkTab0 (W, CaseSens, nil, arg)
if p.Error.yes then
return p.MsgError()
else
return Idx
end
end --RStrIdxChkTab
local function IdxOrNotFound (ParId, W, Idx, ...)
local Err = {}
if Idx == 0 then
local tab = unpack(arg)
for _, Wd in ipairs(tab) do
if type(Wd) == 'table' then
table.insert (Err, table.concat(Wd,p.ParaSep))
else
table.insert (Err, Wd)
end
end
ParamErrorS (ParId, I18nStr (RS.SNotFoundInTab, W, table.concat(Err,', ')))
else
return Idx
end
end --IdxOrNotFound
function p.StrIdxChkTabE (Args, ParId, CaseSens, Default, ...)
if p.Error.yes then return end
local W = p.Str_Par (Args, ParId, Default)
local Idx = StrIdxChkTab0 (W, CaseSens, Default, arg)
if p.Error.yes then
return p.MsgError()
else
return IdxOrNotFound (ParId, W, Idx, arg)
end
end--StrIdxChkTabE
function p.RStrIdxChkTabE (Args, ParId, CaseSens, ...)
if p.Error.yes then return end
local W = p.RStr_Par (Args, ParId)
local Idx = StrIdxChkTab0 (W, CaseSens, nil, arg)
if p.Error.yes then
return p.MsgError()
else
return IdxOrNotFound (ParId, W, Idx, arg)
end
end --RStrIdxChkTabE
-----
local function InRange (Num, ParId, MinItemNum, MaxItemNum)
out = ((MinItemNum ~= nil) and (Num < MinItemNum)) or ((MaxItemNum ~= nil) and (Num > MaxItemNum))
if out then
if MaxItemNum ~= nil then
ParamErrorS (ParId, I18nStr (RS.STabIsNotInRange, Num, tostring(MinItemNum), tostring(MaxItemNum)))
else
ParamErrorS (ParId, I18nStr (RS.STabFewItems, Num, tostring(MinItemNum)))
end
end
return not out
end--InRange
function p.StrTab_1Par (Args, ParId, Sep, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
if Sep == nil then
error ('Undefined items separator') -- Don't translate, it ies only for debug
end
if OnEmpty == nil then
OnEmpty = 2 --set an empty value error
end
local tab = mw.text.split (p.Str_Par (Args, ParId), Sep)
if p.Error.yes then return end
if InRange (#tab, ParId, MinItemNum, MaxItemNum) then
for I, W in ipairs(tab) do
tab[I] = mw.text.trim (tab[I])
end
if OnEmpty == 0 then
return tab
elseif OnEmpty == 1 then
local tab2 = {}
for _, W in ipairs(tab) do
if W ~= '' then
table.insert (tab2, W)
end
end
return tab2
else
for _, W in ipairs(tab) do
if W == '' then
ParamError (ParId, RS.EmptyValue)
end
end
return tab
end
end
end --StrTab_1Par
function p.NumTab_1Par (Args, ParId, Sep, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
tab = p.StrTab_1Par (Args, ParId, Sep, MinItemNum, MaxItemNum, OnEmpty)
if p.Error.yes then return end
for I, W in ipairs(tab) do
if W ~= nil then
local J = tonumber(W)
if not J then
ParamError (ParId, RS.SIsNotNumber, W)
return tab
else
p.CheckNum (J, Pos, LimInf, LimSup)
if p.Error.yes then return end
tab[I] = J
end
end
end
return tab
end --NumTab_1Par
function p.PosNumTab_1Par (Args, ParId, Sep, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
tab = p.NumTab_1Par (Args, ParId, Sep, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
for _, W in ipairs(tab) do
if W ~= nil then
p.CheckNumIsPos (W, ParId)
end
if p.Error.yes then return end
end
return tab
end --ZeroOrPosNumTab_1Par
function p.ZeroOrPosNumTab_1Par (Args, ParId, Sep, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
tab = p.NumTab_1Par (Args, ParId, Sep, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
for _, W in ipairs(tab) do
if W ~= nil then
p.CheckNumIsZeroOrPos (W, ParId)
end
if p.Error.yes then return end
end
return tab
end --ZeroOrPosNumTab_1Par
function p.IntTab_1Par (Args, ParId, Sep, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
tab = p.NumTab_1Par (Args, ParId, Sep, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
for _, W in ipairs(tab) do
if W ~= nil then
p.CheckNumIsInt (W, ParId)
end
if p.Error.yes then return end
end
return tab
end--IntTab_1Par
function p.PosIntTab_1Par (Args, ParId, Sep, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
tab = p.IntTab_1Par (Args, ParId, Sep, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
for _, W in ipairs(tab) do
if W ~= nil then
p.CheckNumIsPos (W, ParId)
end
if p.Error.yes then return end
end
return tab
end --PosIntTab_1Par
function p.ZeroOrPosIntTab_1Par (Args, ParId, Sep, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
tab = p.IntTab_1Par (Args, ParId, Sep, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
for _, W in ipairs(tab) do
if W ~= nil then
p.CheckNumIsZeroOrPos (W, ParId)
end
if p.Error.yes then return end
end
return tab
end --ZeroOrPosIntTab_1Par
--------
function p.StrTab_NPar (Args, NArgs, ParId, MinItemNum, MaxItemNum, OnEmpty)
local tab = {}
if OnEmpty == nil then
OnEmpty = 2 --set an empty value error
end
function IncInTab (val)
val = mw.text.trim(val)
if OnEmpty == 0 then
if val ~= '' then
table.insert(tab,val)
end
elseif OnEmpty == 1 then
table.insert(tab,val)
else
if val == '' then
ParamError (ParId, RS.EmptyValue)
else
table.insert(tab,val)
end
end
end
if p.Error.yes then return end
if type(ParId) == 'number' then
if ParId == 1 then
for _, v in ipairs(Args) do
IncInTab (v)
if p.Error.yes then return end
end
else
for k = ParId, NArgs do
local S = Args[k]
IncInTab (S)
if p.Error.yes then return end
end
end
elseif type(ParId) == 'string' then
found = false
local Pos = 1
while not found do
local key = string.format (ParId, Pos)
for k, v in pairs(Args) do
if k == key then
IncInTab (v)
if p.Error.yes then return end
found = true
break
end
end
if not found then
break
end
found = false
Pos = Pos + 1
end
elseif type(ParId) == 'table' then
found = false
local Pos = 1
while not found do
for _, b in ipairs(ParId) do
local key = string.format (b, Pos)
for k, v in pairs(Args) do
if k == key then
IncInTab (v)
if p.Error.yes then return end
found = true
break
end
end
if found then
break
end
end
if not found then
break
end
found = false
Pos = Pos + 1
end
end
InRange (#tab, ParId, MinItemNum, MaxItemNum)
return tab, #tab
end --StrTab_NPar
function p.NumTab_NPar (Args, NArgs, ParId, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
local tab = p.StrTab_NPar (Args, NArgs, ParId, MinItemNum, MaxItemNum, OnEmpty)
if p.Error.yes then return end
local Pos = ParId
for I, W in ipairs(tab) do
if W ~= nil then
local J = tonumber(W)
if not J then
ParamError (Pos, RS.SIsNotNumber, W)
else
p.CheckNum (J, Pos, LimInf, LimSup)
if p.Error.yes then return end
tab[I] = J
end
end
Pos = Pos + 1
end
return tab
end --NumTab_NPar
function p.PosNumTab_NPar (Args, NArgs, ParId, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
local tab = p.NumTab_NPar (Args, NArgs, ParId, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
local Pos = ParId
for _, W in ipairs(tab) do
if W ~= nil then
p.CheckNumIsPos (W, Pos)
end
if p.Error.yes then return end
Pos = Pos + 1
end
return tab
end --PosNumTab_NPar
function p.ZeroOrPosNumTab_NPar (Args, NArgs, ParId, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
local tab = p.NumTab_NPar (Args, NArgs, ParId, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
local Pos = ParId
for _, W in ipairs(tab) do
if W ~= nil then
p.CheckNumIsZeroOrPos (W, Pos)
end
if p.Error.yes then return end
Pos = Pos + 1
end
return tab
end --ZeroOrPosNumTab_NPar
function p.IntTab_NPar (Args, NArgs, ParId, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
local tab = p.NumTab_NPar (Args, NArgs, ParId, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
local Pos = ParId
for _, W in ipairs(tab) do
if W ~= nil then
p.CheckSIsInt (W, Pos)
end
if p.Error.yes then return end
Pos = Pos + 1
end
return tab
end --IntTab_NPar
function p.PosIntTab_NPar (Args, NArgs, ParId, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
local tab = p.IntTab_NPar (Args, NArgs, ParId, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
local Pos = ParId
for _, W in ipairs(tab) do
if W ~= nil then
p.CheckNumIsPos (W, Pos)
end
if p.Error.yes then return end
Pos = Pos + 1
end
return tab
end --PosIntTab_NPar
function p.ZeroOrPosIntTab_NPar (Args, NArgs, ParId, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
local tab = p.IntTab_NPar (Args, NArgs, ParId, MinItemNum, MaxItemNum, LimInf, LimSup, OnEmpty)
if p.Error.yes then return end
local Pos = ParId
for _, W in ipairs(tab) do
if W ~= nil then
p.CheckNumIsZeroOrPos (W, Pos)
end
if p.Error.yes then return end
Pos = Pos + 1
end
return tab
end --ZeroOrPosIntTab_NPar
----------
function p.TemplateName(frame)
local S = frame:getParent():getTitle()
return string.sub(S, string.find(S,':')+1)
end
function p.MainTemplateName(frame)
local S = p.TemplateName(frame)
return string.sub (S, 1, #S - S:reverse():find("/"))
end
local function CheckIsStrNotEmpty (v, S)
if v == '' then
error ('"'..S..'" has not assigned value') -- Translation not required
else
return v
end
end --CheckIsStrNotEmpty
function p.CheckIsStr (v, S)
if type(v) == "string" then
return CheckIsStrNotEmpty (v, S)
elseif type(v) == nil then
error ('Not found item for "'..S..'"') -- Translation not required
else
SD.vtos (v)
error ('"'..SD.s..'" (for "'..S..'") is not a string') -- Translation not required
end
end --CheckIsStr
local function WhenNoStrOrTab (v, S)
SD.vtos (v)
error ('"'..SD.s..'" (for "'..S..'") is not a string/table') -- Translation not required
end
function p.CheckIsStrOrTab (v, S)
--It does not allow empty strings
if type(v) == "string" then
return CheckIsStrNotEmpty (v, S)
elseif type(v) == "table" then
for _, vv in ipairs(v) do
if type(vv) == "string" then
CheckIsStrNotEmpty (vv, S)
end
end
return v
else
WhenNoStrOrTab (v, S)
end
end --CheckIsStrOrTab
function p.CheckIsAnyStrOrTab (v, S)
--It allows empty strings
if (type(v) == "string") or (type(v) == "table") then
return v
else
WhenNoStrOrTab (v, S)
end
end --CheckIsAnyStrOrTab
----------------------------------------
function p.rgbToHex(rgb) --not used
local hexadecimal = '#'
for key, value in ipairs(rgb) do
local hex = ''
if (value < 0) or (value > 255) then
error ('Invalid color number: '..value)
end
while value > 0 do
local index = math.fmod(value, 16) + 1
value = math.floor (value/16)
hex = string.sub('0123456789ABCDEF', index, index) .. hex
end
if string.len(hex) == 0 then
hex = '00'
elseif string.len(hex) == 1 then
hex = '0' .. hex
end
hexadecimal = hexadecimal .. hex
end
return hexadecimal
end --p.rgbToHex
function p._ReverseColor0 (rgb) --not used
return p.rgbToHex ({255-GetRValue(rgb), 255-GetGValue(rgb), 255-GetBValue(rgb)});
end
function p._ReverseColor (rgb)
-- rgb is a string with 6 characters in format NNNNNN i.e. '008000'
-- (Better contrast than _ReverseColor0 for some colors: i.g. grey)
local BreakGrey = 150
local BreakColor = 180
local RValue = GetRValue (rgb)
local BValue = GetBValue (rgb)
local GValue = GetGValue (rgb)
if (RValue < BreakGrey) and (GValue < BreakGrey) and (BValue < BreakGrey) then
return 'White'
elseif (RValue >= BreakGrey) and (GValue >= BreakGrey) and (BValue >= BreakGrey) then
return 'Black'
elseif (RValue > BreakColor) and (GValue > BreakColor) then
return 'Blue'
elseif (RValue > BreakColor) and (BValue > BreakColor) then
return 'Green'
elseif (GValue > BreakColor) and (BValue > BreakColor) then
return 'Red'
elseif (RValue > BreakColor) then
return 'Aqua' --Blue + Green
elseif (GValue > BreakColor) then
return 'Fuchsia' --Red + Blue
elseif (BValue > BreakColor) then
return 'Yellow' --Red + Green
else
return 'White'
end
end --_ReverseColor
function p.ReverseColor (frame)
local args = p.GetArgs (frame)
local color = p.RColor_Par (args, 1)
return p._ReverseColor (color)
end --ReverseColor
function p._color_black_contrast (color)
local colors = {
GetRValue(color),
GetGValue(color),
GetBValue(color),
}
local dif = math.max (colors[1], colors[2], colors[3]) - math.min (colors[1], colors[2], colors[3])
local val = 0.28*colors[1] + 0.64*colors[2] + 0.08*colors[3]
local to_subtract = math.abs(dif-255)
local to_dif = 128-math.abs(val-128)
local to_subtract2 = to_subtract * to_dif * 0.002
local res = math.floor ((val - to_subtract2) + 0.5)
return res
end --_color_black_contrast
function p.color_black_contrast (frame)
-- Determine the luminosity of a color, with some corrections for grays,
-- for the background of an overlay text, in part from:
-- https://www.johndcook.com/blog/2009/08/24/algorithms-convert-color-grayscale/
local args = p.GetArgs (frame)
local color = p.RColor_Par (args, 1)
return p._color_black_contrast (color)
end --color_black_contrast
function p._txtcolor_for_bg (rgb)
if p._color_black_contrast (rgb) < 90 then
return 'white'
else
return 'black'
end
end --_txtcolor_for_bg
function p.txtcolor_for_bg (frame)
-- For better readability, determine whether the color of the letters
-- should be white or black
-- depending on the background color.
local args = p.GetArgs (frame)
local color = p.RColor_Par (args, 1)
return p._txtcolor_for_bg (color)
end --txtcolor_for_bg
----------------------------------------
return p