Jump to content
Toggle menu
  • 8 articles
  • 75 files
  • 7 users
  • 37.8K edits
Neodyland Wiki
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Module:TemplateBox: Difference between revisions

From Neodyland Wiki
m copy from sandbox
m updating from sandbox
Line 148: Line 148:
         extract = function(item, renderCell)
         extract = function(item, renderCell)
             local label, alias, param = item.label, "", item.key
             local label, alias, param = item.label, "", item.key
            if #label == 0 then
                label = param
            end
             renderCell(label)
             renderCell(label)
             param = '<code>' .. param .. '</code>'
             param = '<code>' .. param .. '</code>'
Line 181: Line 178:
             local stat = msg('param-optional')
             local stat = msg('param-optional')
             if item.required then
             if item.required then
                 stat = msg('param-required')
                 stat = '<b>' .. msg('param-required') .. '</b>'
             elseif item.deprecated then
             elseif item.deprecated then
                 stat = msg('param-deprecated')
                 stat = msg('param-deprecated')

Revision as of 11:58, 16 August 2013

Module documentation[ create · purge ]
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
            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 = '<b>' .. msg('param-required') .. '</b>'
            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
Cookies help us deliver our services. By using our services, you agree to our use of cookies.