Module:Infobox: Difference between revisions

From BitProjects
Jump to navigation Jump to search
Infobox>Frietjes
Undid revision 782833995 by Jc86035 (talk) looks like this caused some serious problems, will require more testing (see, e.g, my talk page)
No edit summary
 
(39 intermediate revisions by 11 users not shown)
Line 1: Line 1:
--
local p = {};
-- This module implements {{Infobox}}
--
local p = {}


local navbar = require('Module:Navbar')._navbar
local yesno = require('Module:Yesno')


local args = {}
local function _renderLine( frame, args, i )
local origArgs
if args[ 'заголовок' .. i ] and args[ 'заголовок' .. i ] == '-' then
local root
return ''
elseif args[ 'заголовок' .. i ] and args[ 'заголовок' .. i ] ~= '' then
local style = ( args[ 'стиль_заголовков' ] or '' ) .. ( args[ 'стиль_заголовка' .. i ] or '' );
local class = ( args[ 'класс' .. i ] or '' );
return '\n<tr>\n<th colspan="2" scope="colgroup" class="infobox-header ' .. class .. '" style="' .. style .. '">' ..
args[ 'заголовок' .. i ] ..
'</th>\n</tr>';
end
if args[ 'блок' .. i ] and args[ 'блок' .. i ] ~= '' then
return args[ 'блок' .. i ];
end


local function union(t1, t2)
local text = args[ 'текст' .. i ] or '';
    -- Returns the union of the values of two tables, as a sequence.
if args[ 'викиданные' .. i ] and args[ 'викиданные' .. i ] ~= '' then
    local vals = {}
text = frame:expandTemplate{ title = 'Wikidata', args = {
    for k, v in pairs(t1) do
args[ 'викиданные' .. i ],
        vals[v] = true
text,
    end
from = args[ 'from' ] or ''
    for k, v in pairs(t2) do
} };
        vals[v] = true
end
    end
    local ret = {}
    for k, v in pairs(vals) do
        table.insert(ret, k)
    end
    return ret
end
 
local function getArgNums(prefix)
    -- Returns a table containing the numbers of the arguments that exist
    -- for the specified prefix. For example, if the prefix was 'data', and
    -- 'data1', 'data2', and 'data5' exist, it would return {1, 2, 5}.
    local nums = {}
    for k, v in pairs(args) do
        local num = tostring(k):match('^' .. prefix .. '([1-9]%d*)$')
        if num then table.insert(nums, tonumber(num)) end
    end
    table.sort(nums)
    return nums
end


local function addRow(rowArgs)
     if text ~= '' then
    -- Adds a row to the infobox, with either a header cell
local label = args[ 'метка' .. i ] or '';
    -- or a label/data cell combination.
     if rowArgs.header then
        root
            :tag('tr')
                :addClass(rowArgs.rowclass)
                :cssText(rowArgs.rowstyle)
                :attr('id', rowArgs.rowid)
                :tag('th')
                    :attr('colspan', 2)
                    :attr('id', rowArgs.headerid)
                    :addClass(rowArgs.class)
                    :addClass(args.headerclass)
                    :css('text-align', 'center')
                    :cssText(args.headerstyle)
                    :cssText(rowArgs.rowcellstyle)
                    :wikitext(rowArgs.header)
    elseif rowArgs.data then
        local row = root:tag('tr')
        row:addClass(rowArgs.rowclass)
        row:cssText(rowArgs.rowstyle)
        row:attr('id', rowArgs.rowid)
        if rowArgs.label then
            row
                :tag('th')
                    :attr('scope', 'row')
                    :attr('id', rowArgs.labelid)
                    :cssText(args.labelstyle)
                    :cssText(rowArgs.rowcellstyle)
                    :wikitext(rowArgs.label)
                    :done()
        end
       
        local dataCell = row:tag('td')
        if not rowArgs.label then
            dataCell
                :attr('colspan', 2)
                :css('text-align', 'center')
        end
        dataCell
            :attr('id', rowArgs.dataid)
            :addClass(rowArgs.class)
            :cssText(rowArgs.datastyle)
            :cssText(rowArgs.rowcellstyle)
            :newline()
            :wikitext(rowArgs.data)
    end
end
 
local function renderTitle()
    if not args.title then return end
 
    root
        :tag('caption')
            :addClass(args.titleclass)
            :cssText(args.titlestyle)
            :wikitext(args.title)
end
 
local function renderAboveRow()
    if not args.above then return end
   
    root
        :tag('tr')
            :tag('th')
                :attr('colspan', 2)
                :addClass(args.aboveclass)
                :css('text-align', 'center')
                :css('font-size', '125%')
                :css('font-weight', 'bold')
                :cssText(args.abovestyle)
                :wikitext(args.above)
end
 
local function renderBelowRow()
    if not args.below then return end
   
    root
        :tag('tr')
            :tag('td')
                :attr('colspan', '2')
                :addClass(args.belowclass)
                :css('text-align', 'center')
                :cssText(args.belowstyle)
                :newline()
                :wikitext(args.below)
end


local function renderSubheaders()
    local class = args[ 'класс' .. i ] or '';
    if args.subheader then
    if string.find(class, 'noplainlist') == nil and string.find(class, 'nofirstlevel') == nil then
        args.subheader1 = args.subheader
    class = class .. ' plainlist';
    end
    end
    if args.subheaderrowclass then
    if class ~= '' then
        args.subheaderrowclass1 = args.subheaderrowclass
class = ' class="' .. class .. '"';
    end
    end
    local subheadernums = getArgNums('subheader')
    for k, num in ipairs(subheadernums) do
        addRow({
            data = args['subheader' .. tostring(num)],
            datastyle = args.subheaderstyle or args['subheaderstyle' .. tostring(num)],
            class = args.subheaderclass,
            rowclass = args['subheaderrowclass' .. tostring(num)]
        })
    end
end


local function renderImages()
    local style = ( args[ 'стиль_текстов' ] or '' ) .. ( args[ 'стиль_текста' ] or '' ) .. ( args[ 'стиль_текста' .. i ] or '' );
    if args.image then
if label == '' then
        args.image1 = args.image
style = 'text-align:center;' .. style;
    end
end
    if args.caption then
    if style ~= '' then
        args.caption1 = args.caption
    style = ' style="' .. style .. '"';
    end
end
    local imagenums = getArgNums('image')
    for k, num in ipairs(imagenums) do
        local caption = args['caption' .. tostring(num)]
        local data = mw.html.create():wikitext(args['image' .. tostring(num)])
        if caption then
            data
                :tag('div')
                    :cssText(args.captionstyle)
                    :wikitext(caption)
        end
        addRow({
            data = tostring(data),
            datastyle = args.imagestyle,
            class = args.imageclass,
            rowclass = args['imagerowclass' .. tostring(num)]
        })
    end
end


local function renderRows()
if label ~= '' then
    -- Gets the union of the header and data argument numbers,
    local labelClass = args[ 'класс_меток' ] or '';
    -- and renders them all in order using addRow.
    if string.find(labelClass, 'noplainlist') == nil and string.find(labelClass, 'nofirstlevel') == nil then
    local rownums = union(getArgNums('header'), getArgNums('data'))
    labelClass = labelClass .. ' plainlist';
    table.sort(rownums)
end
    for k, num in ipairs(rownums) do
    if labelClass ~= '' then
        addRow({
    labelClass = ' class="' .. labelClass .. '"';
            header = args['header' .. tostring(num)],
end
            label = args['label' .. tostring(num)],
            data = args['data' .. tostring(num)],
    local labelStyle = ( args[ 'стиль_меток' ] or '' ) .. ( args[ 'стиль_метки' .. i ] or '' );
            datastyle = args.datastyle,
    if labelStyle ~= '' then
            class = args['class' .. tostring(num)],
    labelStyle = ' style="' .. labelStyle .. '"';
            rowclass = args['rowclass' .. tostring(num)],
end
            rowstyle = args['rowstyle' .. tostring(num)],
            rowcellstyle = args['rowcellstyle' .. tostring(num)],
            dataid = args['dataid' .. tostring(num)],
            labelid = args['labelid' .. tostring(num)],
            headerid = args['headerid' .. tostring(num)],
            rowid = args['rowid' .. tostring(num)]
        })
    end
end


local function renderNavBar()
return '\n<tr>\n<th scope="row"' .. labelClass .. labelStyle .. '>' .. label .. '</th>' ..
    if not args.name then return end
    '\n<td' .. class .. style .. '>\n' .. text .. '</td>\n</tr>';
end
    return '\n<tr>\n<td colspan="2"' .. class .. style .. '>\n' .. text .. '</td>\n</tr>';
end    
      
      
    root
return '';
        :tag('tr')
            :tag('td')
                :attr('colspan', '2')
                :css('text-align', 'right')
                :wikitext(navbar{
                    args.name,
                    mini = 1,
                })
end
end


local function renderItalicTitle()
local function maxNumber ( args )
    local italicTitle = args['italic title'] and mw.ustring.lower(args['italic title'])
local maxNumber = 0
    if italicTitle == '' or italicTitle == 'force' or italicTitle == 'yes' then
for argName, _ in pairs(args) do
        root:wikitext(mw.getCurrentFrame():expandTemplate({title = 'italic title'}))
local argNumber = mw.ustring.match(argName, '^[^0-9]+([0-9]+)$')
    end
if argNumber and tonumber(argNumber) > maxNumber then
maxNumber = tonumber(argNumber)
end
end
return maxNumber
end
end


local function renderTrackingCategories()
function p.renderLine( frame )
    if args.decat ~= 'yes' then
local args = frame:getParent().args;
        if #(getArgNums('data')) == 0 and mw.title.getCurrentTitle().namespace == 0 then
return _renderLine(frame, args, '')
            root:wikitext('[[Category:Articles which use infobox templates with no data rows]]')
        end
        if args.child == 'yes' and args.title then
            root:wikitext('[[Category:Pages which use embedded infobox templates with the title parameter]]')
        end
    end
end
end


local function _infobox()
function p.renderLines( frame )
    -- Specify the overall layout of the infobox, with special settings
local args = frame:getParent().args;
    -- if the infobox is used as a 'child' inside another infobox.
    if args.child ~= 'yes' then
local res = ''
        root = mw.html.create('table')
local header, text = '', ''
       
        root
local autoHeaders = yesno(args [ 'автозаголовки' ] or 'false', false)
            :addClass('infobox')
            :addClass(args.bodyclass)
for i = 1, maxNumber(args) do
           
if args[ 'заголовок' .. i ] and args[ 'заголовок' .. i ] ~= '' then
            if args.subbox == 'yes' then
if text ~= '' or not autoHeaders then
                root
res = res .. header .. text
                    :css('padding', '0')
end
                    :css('border', 'none')
header, text = _renderLine(frame, args, i), ''
                    :css('margin', '-3px')
else
                    :css('width', 'auto')
text = text .. _renderLine(frame, args, i)
                    :css('min-width', '100%')
end
                    :css('font-size', '100%')
end
                    :css('clear', 'none')
if text ~= '' or not autoHeaders then
                    :css('float', 'none')
res = res .. header .. text
                    :css('background-color', 'transparent')
end
            else
                root
return res
                    :css('width', '22em')
            end
        root
            :cssText(args.bodystyle)
   
        renderTitle()
        renderAboveRow()
    else
        root = mw.html.create()
       
        root
            :wikitext(args.title)
    end
 
    renderSubheaders()
    renderImages()
    renderRows()
    renderBelowRow() 
    renderNavBar()
    renderItalicTitle()
    renderTrackingCategories()
   
    return tostring(root)
end
end


local function preprocessSingleArg(argName)
return p;
    -- If the argument exists and isn't blank, add it to the argument table.
    -- Blank arguments are treated as nil to match the behaviour of ParserFunctions.
    if origArgs[argName] and origArgs[argName] ~= '' then
        args[argName] = origArgs[argName]
    end
end
 
local function preprocessArgs(prefixTable, step)
    -- Assign the parameters with the given prefixes to the args table, in order, in batches
    -- of the step size specified. This is to prevent references etc. from appearing in the
    -- wrong order. The prefixTable should be an array containing tables, each of which has
    -- two possible fields, a "prefix" string and a "depend" table. The function always parses
    -- parameters containing the "prefix" string, but only parses parameters in the "depend"
    -- table if the prefix parameter is present and non-blank.
    if type(prefixTable) ~= 'table' then
        error("Non-table value detected for the prefix table", 2)
    end
    if type(step) ~= 'number' then
        error("Invalid step value detected", 2)
    end
   
    -- Get arguments without a number suffix, and check for bad input.
    for i,v in ipairs(prefixTable) do
        if type(v) ~= 'table' or type(v.prefix) ~= "string" or (v.depend and type(v.depend) ~= 'table') then
            error('Invalid input detected to preprocessArgs prefix table', 2)
        end
        preprocessSingleArg(v.prefix)
        -- Only parse the depend parameter if the prefix parameter is present and not blank.
        if args[v.prefix] and v.depend then
            for j, dependValue in ipairs(v.depend) do
                if type(dependValue) ~= 'string' then
                    error('Invalid "depend" parameter value detected in preprocessArgs')
                end
                preprocessSingleArg(dependValue)
            end
        end
    end
 
    -- Get arguments with number suffixes.
    local a = 1 -- Counter variable.
    local moreArgumentsExist = true
    while moreArgumentsExist == true do
        moreArgumentsExist = false
        for i = a, a + step - 1 do
            for j,v in ipairs(prefixTable) do
                local prefixArgName = v.prefix .. tostring(i)
                if origArgs[prefixArgName] then
                    moreArgumentsExist = true -- Do another loop if any arguments are found, even blank ones.
                    preprocessSingleArg(prefixArgName)
                end
                -- Process the depend table if the prefix argument is present and not blank, or
                -- we are processing "prefix1" and "prefix" is present and not blank, and
                -- if the depend table is present.
                if v.depend and (args[prefixArgName] or (i == 1 and args[v.prefix])) then
                    for j,dependValue in ipairs(v.depend) do
                        local dependArgName = dependValue .. tostring(i)
                        preprocessSingleArg(dependArgName)
                    end
                end
            end
        end
        a = a + step
    end
end
function p.infobox(frame)
    -- If called via #invoke, use the args passed into the invoking template.
    -- Otherwise, for testing purposes, assume args are being passed directly in.
    if frame == mw.getCurrentFrame() then
        origArgs = frame:getParent().args
    else
        origArgs = frame
    end
   
    -- Parse the data parameters in the same order that the old {{infobox}} did, so that
    -- references etc. will display in the expected places. Parameters that depend on
    -- another parameter are only processed if that parameter is present, to avoid
    -- phantom references appearing in article reference lists.
    preprocessSingleArg('child')
    preprocessSingleArg('bodyclass')
    preprocessSingleArg('subbox')
    preprocessSingleArg('bodystyle')
    preprocessSingleArg('title')
    preprocessSingleArg('titleclass')
    preprocessSingleArg('titlestyle')
    preprocessSingleArg('above')
    preprocessSingleArg('aboveclass')
    preprocessSingleArg('abovestyle')
    preprocessArgs({
        {prefix = 'subheader', depend = {'subheaderstyle', 'subheaderrowclass'}}
    }, 10)
    preprocessSingleArg('subheaderstyle')
    preprocessSingleArg('subheaderclass')
    preprocessArgs({
        {prefix = 'image', depend = {'caption', 'imagerowclass'}}
    }, 10)
    preprocessSingleArg('captionstyle')
    preprocessSingleArg('imagestyle')
    preprocessSingleArg('imageclass')
    preprocessArgs({
        {prefix = 'header'},
        {prefix = 'data', depend = {'label'}},
        {prefix = 'rowclass'},
        {prefix = 'rowstyle'},
        {prefix = 'rowcellstyle'},
        {prefix = 'class'},
        {prefix = 'dataid'},
        {prefix = 'labelid'},
        {prefix = 'headerid'},
        {prefix = 'rowid'}
    }, 50)
    preprocessSingleArg('headerclass')
    preprocessSingleArg('headerstyle')
    preprocessSingleArg('labelstyle')
    preprocessSingleArg('datastyle')
    preprocessSingleArg('below')
    preprocessSingleArg('belowclass')
    preprocessSingleArg('belowstyle')
    preprocessSingleArg('name')
    args['italic title'] = origArgs['italic title'] -- different behaviour if blank or absent
    preprocessSingleArg('decat')
    return _infobox()
end
return p

Latest revision as of 00:08, 28 September 2025

Documentation for this module may be created at Module:Infobox/doc

local p = {};

local yesno = require('Module:Yesno')

local function _renderLine( frame, args, i )
	if args[ 'заголовок' .. i ] and args[ 'заголовок' .. i ] == '-' then
		return ''
	elseif args[ 'заголовок' .. i ] and args[ 'заголовок' .. i ] ~= '' then
		local style = ( args[ 'стиль_заголовков' ] or '' ) .. ( args[ 'стиль_заголовка' .. i ] or '' );
		local class = ( args[ 'класс' .. i ] or '' );
		return '\n<tr>\n<th colspan="2" scope="colgroup" class="infobox-header ' .. class .. '" style="' .. style .. '">' ..
			args[ 'заголовок' .. i ] ..
			'</th>\n</tr>';
	end
	
	if args[ 'блок' .. i ] and args[ 'блок' .. i ] ~= '' then
		return args[ 'блок' .. i ];
	end

	local text = args[ 'текст' .. i ] or '';
	if args[ 'викиданные' .. i ] and args[ 'викиданные' .. i ] ~= '' then
		text = frame:expandTemplate{ title = 'Wikidata', args = {
			args[ 'викиданные' .. i ],
			text,
			from = args[ 'from' ] or ''
		} };
	end

    if text ~= '' then
		local label = args[ 'метка' .. i ] or '';

    	local class = args[ 'класс' .. i ] or '';
    	if string.find(class, 'noplainlist') == nil and string.find(class, 'nofirstlevel') == nil then
    		class = class .. ' plainlist';
    	end
    	if class ~= '' then
			class = ' class="' .. class .. '"';
    	end

    	local style = ( args[ 'стиль_текстов' ] or '' ) .. ( args[ 'стиль_текста' ] or '' ) .. ( args[ 'стиль_текста' .. i ] or '' );
		if label == '' then
			style = 'text-align:center;' .. style;
		end
    	if style ~= '' then
    		style = ' style="' .. style .. '"';
		end

		if label ~= '' then
	    	local labelClass = args[ 'класс_меток' ] or '';
	    	if string.find(labelClass, 'noplainlist') == nil and string.find(labelClass, 'nofirstlevel') == nil then
    			labelClass = labelClass .. ' plainlist';
			end
	    	if labelClass ~= '' then
	    		labelClass = ' class="' .. labelClass .. '"';
			end
	
	    	local labelStyle = ( args[ 'стиль_меток' ] or '' ) .. ( args[ 'стиль_метки' .. i ] or '' );
	    	if labelStyle ~= '' then
	    		labelStyle = ' style="' .. labelStyle .. '"';
			end

			return '\n<tr>\n<th scope="row"' .. labelClass .. labelStyle .. '>' .. label .. '</th>' ..
	    		'\n<td' .. class .. style .. '>\n' .. text .. '</td>\n</tr>';
		end
		
	    return '\n<tr>\n<td colspan="2"' .. class .. style .. '>\n' .. text .. '</td>\n</tr>';
	end	    
    
	return '';
end

local function maxNumber ( args )
	local maxNumber = 0
	for argName, _ in pairs(args) do
		local argNumber = mw.ustring.match(argName, '^[^0-9]+([0-9]+)$')
		if argNumber and tonumber(argNumber) > maxNumber then
			maxNumber = tonumber(argNumber)
		end
	end
	return maxNumber
end

function p.renderLine( frame )
	local args = frame:getParent().args;
	return _renderLine(frame, args, '')
end

function p.renderLines( frame )
	local args = frame:getParent().args;
	
	local res = ''
	local header, text = '', ''
	
	local autoHeaders = yesno(args [ 'автозаголовки' ] or 'false', false)
	
	for i = 1, maxNumber(args) do
		if args[ 'заголовок' .. i ] and args[ 'заголовок' .. i ] ~= '' then
			if text ~= '' or not autoHeaders then
				res = res .. header .. text
			end
			header, text = _renderLine(frame, args, i), ''
		else
			text = text .. _renderLine(frame, args, i)
		end
	end
	if text ~= '' or not autoHeaders then
		res = res .. header .. text
	end
	
	return res
end

return p;