Module:TemplateBox: Difference between revisions
From Neodyland Wiki
More actions
m Documentation |
m copy from sandbox |
||
| Line 1: | Line 1: | ||
--[[ | |||
@exports | |||
args2table( args, onGetKey, sets ) | |||
paramtable( frame ) | |||
templatedata( frame ) | |||
]] | |||
local p = {} | local p = {} | ||
| Line 11: | Line 18: | ||
local messagePrefix = "templatedata-doc-" | |||
local i18n = {} | |||
i18n['params'] = "Template parameters" | |||
i18n['param-name'] = "Parameter" | |||
i18n['param-desc'] = "Description" | |||
i18n['param-type'] = "Type" | |||
i18n['param-default'] = "Default" | |||
i18n['param-status'] = "Status" | |||
i18n['param-optional'] = "optional" | |||
i18n['param-required'] = "required" | |||
i18n['param-deprecated'] = "deprecated" | |||
i18n['param-empty'] = "empty" | |||
--! From [[:de:Modul:Expr]]; by [[:de:User:PerfektesChaos]]; | |||
--! Derivative work: Rillke | |||
local userLang = mw.message.newRawMessage( '{{int:lang}}' ):parse() | |||
-- Required to determine in which languages the interface texts without langcode are | |||
local contentLangcode = mw.language.getContentLanguage():getCode() | |||
local function msg( key ) | |||
-- Retrieve localized message string in content language | |||
-- Precondition: | |||
-- key -- string; message ID | |||
-- Postcondition: | |||
-- Return some message string | |||
-- Uses: | |||
-- > messagePrefix | |||
-- > i18n | |||
-- > userLang | |||
-- mw.message.new() | |||
local m = mw.message.new( messagePrefix .. key ) | |||
local r = false | |||
if m:isBlank() then | |||
r = i18n[ key ] | |||
else | |||
m:inLanguage( userLang ) | |||
r = m:plain() | |||
end | |||
if not r then | |||
r = "(((".. key .. ")))" | |||
end | |||
return r | |||
end -- msg() | |||
-- A "hash" / table of everything TemplateData takes | -- A "hash" / table of everything TemplateData takes | ||
| Line 80: | Line 125: | ||
required = false, | required = false, | ||
default = '', | default = '', | ||
t = ' | t = 'string', | ||
alias = 'def' | alias = 'def' | ||
}, | }, | ||
| Line 95: | Line 140: | ||
} | } | ||
-- sets will be treated differently because we can only have a plain structure in wikitext | -- sets will be treated differently because we can only have a plain structure in wikitext | ||
} | |||
local tableLayout = { | |||
{ | |||
col = 'param-name', | |||
cols = 2, | |||
width = '20%', | |||
extract = function(item, renderCell) | |||
local label, alias, param = item.label, "", item.key | |||
if #label == 0 then | |||
label = param | |||
end | |||
renderCell(label) | |||
param = '<code>' .. param .. '</code>' | |||
if item.aliases then | |||
alias = '<tt>' .. table.concat(alias, '</tt>, <tt>') .. '</tt>' | |||
param = param .. '<br /><span style="mw-templatedata-doc-param-alias">' .. alias .. '</span>' | |||
end | |||
renderCell(param) | |||
end | |||
}, { | |||
col = 'param-desc', | |||
width = '60%', | |||
extract = function(item, renderCell) | |||
renderCell(item.description) | |||
end | |||
}, { | |||
col = 'param-default', | |||
width = '10%', | |||
extract = function(item, renderCell) | |||
local def = item.default or '' | |||
if #def == 0 then | |||
def = '<span class="mw-templatedata-doc-muted" style="color:#777; font-variant:small-caps">' .. msg('param-empty') .. '</span>' | |||
end | |||
renderCell(def) | |||
end | |||
}, { | |||
col = 'param-status', | |||
width = '10%', | |||
extract = function(item, renderCell) | |||
local stat = msg('param-optional') | |||
if item.required then | |||
stat = msg('param-required') | |||
elseif item.deprecated then | |||
stat = msg('param-deprecated') | |||
end | |||
renderCell(stat) | |||
end | |||
} | |||
} | } | ||
| Line 115: | Line 208: | ||
init( paraminfoTLParams ) | init( paraminfoTLParams ) | ||
-- | ------------------------------------------------------ | ||
-- | ------------------- GENERAL PART --------------------- | ||
------------------------------------------------------ | |||
function p.args2table(args, onGetKey, sets, asParamArray) | |||
-- All kind of strange stuff with the arguments is done, so play safe and make a copy | -- All kind of strange stuff with the arguments is done, so play safe and make a copy | ||
local pargs = mw.clone( | local pargs = mw.clone( args ) | ||
-- Array-like table containing all parameter-numbers that were passed | -- Array-like table containing all parameter-numbers that were passed | ||
local templateArgs = {} | local templateArgs = {} | ||
-- Arguments that are localized (i.e. the user passed 1desc-en=English description of parameter one) | -- Arguments that are localized (i.e. the user passed 1desc-en=English description of parameter one) | ||
local i18nTemplateArgs = {} | local i18nTemplateArgs = {} | ||
-- Ensure that tables end up as array/object (esp. when they are empty) | -- Ensure that tables end up as array/object (esp. when they are empty) | ||
local tdata = {description="", params={}, sets={}} | |||
local tdata = | local isArray = { __tostring = function() return "JSON array" end } isArray.__index = isArray | ||
setmetatable(tdata.sets, isArray) | |||
onGetKey = onGetKey or function( prefix, alias, param ) | |||
local key, key2, tdkey, tdkey2 | |||
key = prefix .. (alias or param) | |||
key2 = prefix .. param | |||
tdkey = key .. '-td' | |||
tdkey2 = key2 .. '-td' | |||
return tdkey, tdkey2, key, key2 | |||
end | |||
local extractData = function( pi, number ) | local extractData = function( pi, number ) | ||
local prefix = number or '' | local prefix = number or '' | ||
local | local ppv, paramVal | ||
local key1, key2, key3, key4 | |||
local paramKey, paramTable | local paramKey, paramTable | ||
if number then | if number then | ||
| Line 141: | Line 241: | ||
paramKey = tostring( number ) | paramKey = tostring( number ) | ||
end | end | ||
paramTable = tdata.params[paramKey] | paramTable = {} | ||
if asParamArray then | |||
paramTable.key = paramKey | |||
table.insert(tdata.params, paramTable) | |||
else | |||
tdata.params[paramKey] = paramTable | |||
end | |||
end | end | ||
for p, info in pairs( pi ) do | for p, info in pairs( pi ) do | ||
key1, key2, key3, key4 = onGetKey(prefix, info.alias, p) | |||
ppv = pargs[key1] or pargs[key2] or pargs[key3] or pargs[key4] or info.default | |||
ppv = pargs[ | |||
-- Do we have a multilingual item? | -- Do we have a multilingual item? | ||
paramVal = i18nTemplateArgs[ | paramVal = i18nTemplateArgs[key1] or i18nTemplateArgs[key2] or i18nTemplateArgs[key3] or i18nTemplateArgs[key4] | ||
if 'table' == type( paramVal ) then | if 'table' == type( paramVal ) then | ||
if (nil == paramVal[contentLangcode]) then | if (nil == paramVal[contentLangcode]) then | ||
| Line 210: | Line 313: | ||
end | end | ||
-- Now, treat sets | -- Now, treat sets | ||
if sets then | |||
key1 = prefix .. 'set-td' | |||
key2 = prefix .. 'set' | |||
paramVal = pargs[key1] or pargs[key2] | |||
if paramVal then | |||
local found = false | |||
for i, s in ipairs( tdata.sets ) do | |||
if s.label == paramVal then | |||
found = | table.insert( s.params, p ) | ||
found = true | |||
end | |||
end | |||
if not found then | |||
table.insert( tdata.sets, { | |||
label = paramVal, | |||
params = { p } | |||
} ) | |||
end | end | ||
end | end | ||
end | end | ||
| Line 234: | Line 339: | ||
mw.log(warning) | mw.log(warning) | ||
tdata.description = warning | tdata.description = warning | ||
return | return tdata, 0; | ||
end | end | ||
| Line 267: | Line 372: | ||
end | end | ||
-- Then, start building the actual template | -- Then, start building the actual template | ||
extractData( paraminfoTemplate ) | if not asParamArray then | ||
extractData( paraminfoTemplate ) | |||
end | |||
for i, number in pairs( templateArgs ) do | for i, number in pairs( templateArgs ) do | ||
extractData( paraminfoTLParams, number ) | extractData( paraminfoTLParams, number ) | ||
end | end | ||
return tdata, #templateArgs | |||
end | |||
------------------------------------------------------ | |||
------------ CUSTOM PARAMETER TABLE PART ------------- | |||
------------------------------------------------------ | |||
function p.paramtable(frame) | |||
local pargs = ( frame:getParent() or {} ).args or {} | |||
local onGetKey, tdata, paramLen | |||
if 'only' == pargs.useTemplateData then | |||
return 'param table - output suppressed' | |||
end | |||
-- A custom key-pref-function | |||
onGetKey = function( prefix, alias, param ) | |||
local key, key2, tdkey, tdkey2 | |||
key = prefix .. (alias or param) | |||
key2 = prefix .. param | |||
tdkey = key .. '-td' | |||
tdkey2 = key2 .. '-td' | |||
return key2, key, tdkey2, tdkey | |||
end | |||
tdata, paramLen = p.args2table(pargs, onGetKey, false, true) | |||
if 0 == paramLen then | |||
return 'noparams' | |||
end | |||
local row, rows = '', {} | |||
local renderCell = function(wikitext) | |||
if type(wikitext) == 'table' then | |||
wikitext = frame:expandTemplate{ title = 'LangSwitch', args = wikitext } | |||
end | |||
row = row .. '<td>' .. wikitext .. '</td>' | |||
end | |||
-- Create the header | |||
for i, field in ipairs( tableLayout ) do | |||
local style = ' style="width:' .. field.width .. '"' | |||
local colspan = '' | |||
if field.cols then | |||
colspan = ' colspan="' .. field.cols .. '"' | |||
end | |||
local th = '<th' .. style .. colspan .. '>' | |||
row = row .. th .. msg(field.col) .. '</th>' | |||
end | |||
table.insert(rows, row) | |||
-- Now transform the Lua-table into an HTML-table | |||
for i, item in ipairs( tdata.params ) do | |||
row = '' | |||
for i2, field in ipairs( tableLayout ) do | |||
field.extract(item, renderCell) | |||
end | |||
table.insert(rows, row) | |||
end | |||
return '<table class="wikitable templatebox-table"><tr>' .. table.concat(rows, '</tr><tr>') .. '</tr></table>' | |||
end | |||
------------------------------------------------------ | |||
----------------- TEMPLATEDATA PART ------------------ | |||
------------------------------------------------------ | |||
-- A real parser/transformer would look differently but it would likely be much more complex | |||
-- The TemplateData-portion for [[Template:TemplateBox]] | |||
function p.templatedata(frame) | |||
-- Load the JSON-Module which will convert LUA tables into valid JSON | |||
local JSON = require('Module:JSON') | |||
JSON.strictTypes = true | |||
-- Obtain the object containing info | |||
local tdata = p.args2table(( frame:getParent() or {} ).args or {}, nil, true) | |||
-- And finally return the result | -- And finally return the result | ||
return JSON:encode(tdata) | return JSON:encode(tdata) | ||
end | end | ||
return p | return p | ||
Revision as of 11:35, 16 August 2013
This documentation is transcluded from Module:TemplateBox/doc.
--[[
@exports
args2table( args, onGetKey, sets )
paramtable( frame )
templatedata( frame )
]]
local p = {}
-- Helper function, not exposed
function tobool(st)
if type( st ) == 'string' then
return st == 'true'
else
return not not st
end
end
local messagePrefix = "templatedata-doc-"
local i18n = {}
i18n['params'] = "Template parameters"
i18n['param-name'] = "Parameter"
i18n['param-desc'] = "Description"
i18n['param-type'] = "Type"
i18n['param-default'] = "Default"
i18n['param-status'] = "Status"
i18n['param-optional'] = "optional"
i18n['param-required'] = "required"
i18n['param-deprecated'] = "deprecated"
i18n['param-empty'] = "empty"
--! From [[:de:Modul:Expr]]; by [[:de:User:PerfektesChaos]];
--! Derivative work: Rillke
local userLang = mw.message.newRawMessage( '{{int:lang}}' ):parse()
-- Required to determine in which languages the interface texts without langcode are
local contentLangcode = mw.language.getContentLanguage():getCode()
local function msg( key )
-- Retrieve localized message string in content language
-- Precondition:
-- key -- string; message ID
-- Postcondition:
-- Return some message string
-- Uses:
-- > messagePrefix
-- > i18n
-- > userLang
-- mw.message.new()
local m = mw.message.new( messagePrefix .. key )
local r = false
if m:isBlank() then
r = i18n[ key ]
else
m:inLanguage( userLang )
r = m:plain()
end
if not r then
r = "(((".. key .. ")))"
end
return r
end -- msg()
-- A "hash" / table of everything TemplateData takes
-- to ease maintenance.
-- The type is automatically determined if t is omitted.
-- If the type does not match or can't be converted, an error will be thrown!
-- Available types (LUA-Types with exceptions):
-- InterfaceText, boolean, number, selection, table, string
-- selection*: - requires a selection-string of pipe-separated possibilities to be supplied
-- InterfaceText*: A free-form string (no wikitext) in the content-language of the wiki, or,
-- an object containing those strings keyed by language code.
local paraminfoTemplate = {
description = {
required = true,
default = '',
t = 'InterfaceText',
alias = 'desc'
}
}
local paraminfoTLParams = {
label = {
required = false,
default = '',
t = 'InterfaceText'
},
required = {
required = true,
default = false,
extract = function(pargs, number, paramVal)
local req = (pargs[number .. 'stat'] == 'required')
return tobool( paramVal or req )
end
},
description = {
required = false,
default = '',
t = 'InterfaceText',
alias = 'd'
},
deprecated = {
required = true,
default = false,
extract = function(pargs, number, paramVal)
local depr = (pargs[number .. 'stat'] == 'deprecated')
return tobool( paramVal or depr )
end
},
aliases = {
required = false,
default = '',
t = 'table',
extract = function(pargs, number, paramVal)
local key = number .. 'aliases'
local tdkey = key .. '-td'
local aliases = pargs[tdkey] or pargs[key]
if aliases then
aliases = mw.text.split( aliases, '/', true )
end
return aliases
end
},
default = {
required = false,
default = '',
t = 'string',
alias = 'def'
},
type = {
required = false,
default = 'unknown',
t = 'selection',
selection = 'unknown|number|string|string/wiki-user-name|string/wiki-page-name|string/line'
},
inherits = {
required = false,
default = nil,
t = 'string'
}
-- sets will be treated differently because we can only have a plain structure in wikitext
}
local tableLayout = {
{
col = 'param-name',
cols = 2,
width = '20%',
extract = function(item, renderCell)
local label, alias, param = item.label, "", item.key
if #label == 0 then
label = param
end
renderCell(label)
param = '<code>' .. param .. '</code>'
if item.aliases then
alias = '<tt>' .. table.concat(alias, '</tt>, <tt>') .. '</tt>'
param = param .. '<br /><span style="mw-templatedata-doc-param-alias">' .. alias .. '</span>'
end
renderCell(param)
end
}, {
col = 'param-desc',
width = '60%',
extract = function(item, renderCell)
renderCell(item.description)
end
}, {
col = 'param-default',
width = '10%',
extract = function(item, renderCell)
local def = item.default or ''
if #def == 0 then
def = '<span class="mw-templatedata-doc-muted" style="color:#777; font-variant:small-caps">' .. msg('param-empty') .. '</span>'
end
renderCell(def)
end
}, {
col = 'param-status',
width = '10%',
extract = function(item, renderCell)
local stat = msg('param-optional')
if item.required then
stat = msg('param-required')
elseif item.deprecated then
stat = msg('param-deprecated')
end
renderCell(stat)
end
}
}
-- Initialize param info
-- Avoids having to add redundant information to the preceding tables
function init( which )
local setDefault = function(v)
if v.t == nil and v.default ~= nil then
v.t = type( v.default )
end
if v.selection then
v.selection = '|' .. v.selection .. '|'
end
end
for a, v in pairs( which ) do
setDefault(v)
end
end
init( paraminfoTemplate )
init( paraminfoTLParams )
------------------------------------------------------
------------------- GENERAL PART ---------------------
------------------------------------------------------
function p.args2table(args, onGetKey, sets, asParamArray)
-- All kind of strange stuff with the arguments is done, so play safe and make a copy
local pargs = mw.clone( args )
-- Array-like table containing all parameter-numbers that were passed
local templateArgs = {}
-- Arguments that are localized (i.e. the user passed 1desc-en=English description of parameter one)
local i18nTemplateArgs = {}
-- Ensure that tables end up as array/object (esp. when they are empty)
local tdata = {description="", params={}, sets={}}
local isArray = { __tostring = function() return "JSON array" end } isArray.__index = isArray
setmetatable(tdata.sets, isArray)
onGetKey = onGetKey or function( prefix, alias, param )
local key, key2, tdkey, tdkey2
key = prefix .. (alias or param)
key2 = prefix .. param
tdkey = key .. '-td'
tdkey2 = key2 .. '-td'
return tdkey, tdkey2, key, key2
end
local extractData = function( pi, number )
local prefix = number or ''
local ppv, paramVal
local key1, key2, key3, key4
local paramKey, paramTable
if number then
paramKey = mw.text.trim( pargs[number] )
if '' == paramKey then
paramKey = tostring( number )
end
paramTable = {}
if asParamArray then
paramTable.key = paramKey
table.insert(tdata.params, paramTable)
else
tdata.params[paramKey] = paramTable
end
end
for p, info in pairs( pi ) do
key1, key2, key3, key4 = onGetKey(prefix, info.alias, p)
ppv = pargs[key1] or pargs[key2] or pargs[key3] or pargs[key4] or info.default
-- Do we have a multilingual item?
paramVal = i18nTemplateArgs[key1] or i18nTemplateArgs[key2] or i18nTemplateArgs[key3] or i18nTemplateArgs[key4]
if 'table' == type( paramVal ) then
if (nil == paramVal[contentLangcode]) then
paramVal[contentLangcode] = ppv
end
else
paramVal = ppv
end
if 'function' == type( info.extract ) then
if 'string' == type( paramVal ) then
paramVal = mw.text.trim( paramVal )
if '' == paramVal then
paramVal = nil
end
end
paramVal = info.extract( pargs, number, paramVal )
end
local insertValue = function()
if number then
paramTable[p] = paramVal
else
tdata[p] = paramVal
end
end
if info.selection then
if info.selection:find( paramVal, 1, true ) then
insertValue()
end
elseif 'InterfaceText' == info.t then
if ({ table=1, string=1 })[type( paramVal )] then
insertValue()
end
else
local paramType = type( paramVal )
if 'string' == info.t and 'string' == paramType then
paramVal = mw.text.trim( paramVal )
if '' ~= paramVal then
insertValue()
end
elseif 'boolean' == info.t then
paramVal = tobool(paramVal)
insertValue()
elseif 'number' == info.t then
paramVal = tonumber(paramVal)
insertValue()
elseif paramType == info.t then
insertValue()
elseif paramType == 'nil' then
-- Do nothing
else
error( p .. ': Is of type ' .. paramType .. ' but should be of type ' .. (info.t or 'unknown'), 1 )
end
end
end
-- Now, treat sets
if sets then
key1 = prefix .. 'set-td'
key2 = prefix .. 'set'
paramVal = pargs[key1] or pargs[key2]
if paramVal then
local found = false
for i, s in ipairs( tdata.sets ) do
if s.label == paramVal then
table.insert( s.params, p )
found = true
end
end
if not found then
table.insert( tdata.sets, {
label = paramVal,
params = { p }
} )
end
end
end
end
if not pargs.useTemplateData then
local warning = "Warning: Module:TemplateBox - templatedata invoked but not requested by user (setting useTemplateData=1)."
mw.log(warning)
tdata.description = warning
return tdata, 0;
end
-- First, analyse the structure of the provided arguments
for a, v in pairs( pargs ) do
if type( a ) == 'number' then
table.insert( templateArgs, a )
else
local argSplit = mw.text.split( a, '-', true )
local argUnitl = {}
local argAfter = {}
local isTDArg = false
local containsTD = a:find( '-td', 1, true )
for i, part in ipairs( argSplit ) do
if isTDArg or (containsTD == nil and i > 1) then
-- This is likely a language version
table.insert( argAfter, part )
else
table.insert( argUnitl, part )
end
if part == 'td' then
isTDArg = true
end
end
if #argAfter > 0 then
argUnitl = table.concat( argUnitl, '-' )
argAfter = table.concat( argAfter, '-' )
i18nTemplateArgs[argUnitl] = i18nTemplateArgs[argUnitl] or {}
i18nTemplateArgs[argUnitl][argAfter] = v
end
end
end
-- Then, start building the actual template
if not asParamArray then
extractData( paraminfoTemplate )
end
for i, number in pairs( templateArgs ) do
extractData( paraminfoTLParams, number )
end
return tdata, #templateArgs
end
------------------------------------------------------
------------ CUSTOM PARAMETER TABLE PART -------------
------------------------------------------------------
function p.paramtable(frame)
local pargs = ( frame:getParent() or {} ).args or {}
local onGetKey, tdata, paramLen
if 'only' == pargs.useTemplateData then
return 'param table - output suppressed'
end
-- A custom key-pref-function
onGetKey = function( prefix, alias, param )
local key, key2, tdkey, tdkey2
key = prefix .. (alias or param)
key2 = prefix .. param
tdkey = key .. '-td'
tdkey2 = key2 .. '-td'
return key2, key, tdkey2, tdkey
end
tdata, paramLen = p.args2table(pargs, onGetKey, false, true)
if 0 == paramLen then
return 'noparams'
end
local row, rows = '', {}
local renderCell = function(wikitext)
if type(wikitext) == 'table' then
wikitext = frame:expandTemplate{ title = 'LangSwitch', args = wikitext }
end
row = row .. '<td>' .. wikitext .. '</td>'
end
-- Create the header
for i, field in ipairs( tableLayout ) do
local style = ' style="width:' .. field.width .. '"'
local colspan = ''
if field.cols then
colspan = ' colspan="' .. field.cols .. '"'
end
local th = '<th' .. style .. colspan .. '>'
row = row .. th .. msg(field.col) .. '</th>'
end
table.insert(rows, row)
-- Now transform the Lua-table into an HTML-table
for i, item in ipairs( tdata.params ) do
row = ''
for i2, field in ipairs( tableLayout ) do
field.extract(item, renderCell)
end
table.insert(rows, row)
end
return '<table class="wikitable templatebox-table"><tr>' .. table.concat(rows, '</tr><tr>') .. '</tr></table>'
end
------------------------------------------------------
----------------- TEMPLATEDATA PART ------------------
------------------------------------------------------
-- A real parser/transformer would look differently but it would likely be much more complex
-- The TemplateData-portion for [[Template:TemplateBox]]
function p.templatedata(frame)
-- Load the JSON-Module which will convert LUA tables into valid JSON
local JSON = require('Module:JSON')
JSON.strictTypes = true
-- Obtain the object containing info
local tdata = p.args2table(( frame:getParent() or {} ).args or {}, nil, true)
-- And finally return the result
return JSON:encode(tdata)
end
return p