Module:Infobox: Difference between revisions

From BitProjects
Jump to navigation Jump to search
Infobox>Gonnym
Added more options to Italic Title per discussion at Template talk:Infobox#Italics part deux
No edit summary
 
(29 intermediate revisions by 9 users not shown)
Line 1: Line 1:
--
local p = {};
-- This module implements {{Infobox}}
--


local p = {}
local yesno = require('Module:Yesno')


local navbar = require('Module:Navbar')._navbar
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 args = {}
local text = args[ 'текст' .. i ] or '';
local origArgs
if args[ 'викиданные' .. i ] and args[ 'викиданные' .. i ] ~= '' then
local root
text = frame:expandTemplate{ title = 'Wikidata', args = {
args[ 'викиданные' .. i ],
text,
from = args[ 'from' ] or ''
} };
end


local function notempty( s ) return s and s:match( '%S' ) end
    if text ~= '' then
local label = args[ 'метка' .. i ] or '';


local function fixChildBoxes(sval, tt)
    local class = args[ 'класс' .. i ] or '';
if notempty(sval) then
    if string.find(class, 'noplainlist') == nil and string.find(class, 'nofirstlevel') == nil then
local marker = '<span class=special_infobox_marker>'
    class = class .. ' plainlist';
local s = sval
    end
s = mw.ustring.gsub(s, '(<%s*[Tt][Rr])', marker .. '%1')
    if class ~= '' then
s = mw.ustring.gsub(s, '(</[Tt][Rr]%s*>)', '%1' .. marker)
class = ' class="' .. class .. '"';
if s:match(marker) then
    end
s = mw.ustring.gsub(s, marker .. '%s*' .. marker, '')
 
s = mw.ustring.gsub(s, '([\r\n]|-[^\r\n]*[\r\n])%s*' .. marker, '%1')
    local style = ( args[ 'стиль_текстов' ] or '' ) .. ( args[ 'стиль_текста' ] or '' ) .. ( args[ 'стиль_текста' .. i ] or '' );
s = mw.ustring.gsub(s, marker .. '%s*([\r\n]|-)', '%1')
if label == '' then
s = mw.ustring.gsub(s, '(</[Cc][Aa][Pp][Tt][Ii][Oo][Nn]%s*>%s*)' .. marker, '%1')
style = 'text-align:center;' .. style;
s = mw.ustring.gsub(s, '(<%s*[Tt][Aa][Bb][Ll][Ee][^<>]*>%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, '^(%{|[^\r\n]*[\r\n]%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, '([\r\n]%{|[^\r\n]*[\r\n]%s*)' .. marker, '%1')
s = mw.ustring.gsub(s,  marker .. '(%s*</[Tt][Aa][Bb][Ll][Ee]%s*>)', '%1')
s = mw.ustring.gsub(s,  marker .. '(%s*\n|%})', '%1')
end
end
if s:match(marker) then
    if style ~= '' then
local subcells = mw.text.split(s, marker)
    style = ' style="' .. style .. '"';
s = ''
for k = 1, #subcells do
if k == 1 then
s = s .. subcells[k] .. '</' .. tt .. '></tr>'
elseif k == #subcells then
local rowstyle = ' style="display:none"'
if notempty(subcells[k]) then rowstyle = '' end
s = s .. '<tr' .. rowstyle ..'><' .. tt .. ' colspan=2>\n' .. subcells[k]
elseif notempty(subcells[k]) then
if (k % 2) == 0 then
s = s .. subcells[k]
else
s = s .. '<tr><' .. tt .. ' colspan=2>\n' .. subcells[k] .. '</' .. tt .. '></tr>'
end
end
end
end
end
-- the next two lines add a newline at the end of lists for the PHP parser
-- https://en.wikipedia.org/w/index.php?title=Template_talk:Infobox_musical_artist&oldid=849054481
-- remove when [[:phab:T191516]] is fixed or OBE
s = mw.ustring.gsub(s, '([\r\n][%*#;:][^\r\n]*)$', '%1\n')
s = mw.ustring.gsub(s, '^([%*#;:][^\r\n]*)$', '%1\n')
s = mw.ustring.gsub(s, '^([%*#;:])', '\n%1')
s = mw.ustring.gsub(s, '^(%{%|)', '\n%1')
return s
else
return sval
end
end


local function union(t1, t2)
if label ~= '' then
    -- Returns the union of the values of two tables, as a sequence.
    local labelClass = args[ 'класс_меток' ] or '';
    local vals = {}
    if string.find(labelClass, 'noplainlist') == nil and string.find(labelClass, 'nofirstlevel') == nil then
    for k, v in pairs(t1) do
    labelClass = labelClass .. ' plainlist';
        vals[v] = true
end
    end
    if labelClass ~= '' then
    for k, v in pairs(t2) do
    labelClass = ' class="' .. labelClass .. '"';
        vals[v] = true
end
    end
    local ret = {}
    local labelStyle = ( args[ 'стиль_меток' ] or '' ) .. ( args[ 'стиль_метки' .. i ] or '' );
    for k, v in pairs(vals) do
    if labelStyle ~= '' then
        table.insert(ret, k)
    labelStyle = ' style="' .. labelStyle .. '"';
    end
end
    return ret
end


local function getArgNums(prefix)
return '\n<tr>\n<th scope="row"' .. labelClass .. labelStyle .. '>' .. label .. '</th>' ..
    -- Returns a table containing the numbers of the arguments that exist
    '\n<td' .. class .. style .. '>\n' .. text .. '</td>\n</tr>';
    -- for the specified prefix. For example, if the prefix was 'data', and
end
    -- 'data1', 'data2', and 'data5' exist, it would return {1, 2, 5}.
    local nums = {}
    return '\n<tr>\n<td colspan="2"' .. class .. style .. '>\n' .. text .. '</td>\n</tr>';
    for k, v in pairs(args) do
end      
        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)
    -- Adds a row to the infobox, with either a header cell
    -- 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(fixChildBoxes(rowArgs.header, 'th'))
    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)
            :wikitext(fixChildBoxes(rowArgs.data, 'td'))
    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
return '';
        :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(fixChildBoxes(args.above,'th'))
end
end


local function renderBelowRow()
local function maxNumber ( args )
    if not args.below then return end
local maxNumber = 0
   
for argName, _ in pairs(args) do
    root
local argNumber = mw.ustring.match(argName, '^[^0-9]+([0-9]+)$')
        :tag('tr')
if argNumber and tonumber(argNumber) > maxNumber then
            :tag('td')
maxNumber = tonumber(argNumber)
                :attr('colspan', '2')
end
                :addClass(args.belowclass)
end
                :css('text-align', 'center')
return maxNumber
                :cssText(args.belowstyle)
                :wikitext(fixChildBoxes(args.below,'td'))
end
end


local function renderSubheaders()
function p.renderLine( frame )
    if args.subheader then
local args = frame:getParent().args;
        args.subheader1 = args.subheader
return _renderLine(frame, args, '')
    end
    if args.subheaderrowclass then
        args.subheaderrowclass1 = args.subheaderrowclass
    end
    local subheadernums = getArgNums('subheader')
    for k, num in ipairs(subheadernums) do
        addRow({
            data = args['subheader' .. tostring(num)],
            datastyle = args.subheaderstyle,
            rowcellstyle = args['subheaderstyle' .. tostring(num)],
            class = args.subheaderclass,
            rowclass = args['subheaderrowclass' .. tostring(num)]
        })
    end
end
end


local function renderImages()
function p.renderLines( frame )
    if args.image then
local args = frame:getParent().args;
        args.image1 = args.image
    end
local res = ''
    if args.caption then
local header, text = '', ''
        args.caption1 = args.caption
    end
local autoHeaders = yesno(args [ 'автозаголовки' ] or 'false', false)
    local imagenums = getArgNums('image')
    for k, num in ipairs(imagenums) do
for i = 1, maxNumber(args) do
        local caption = args['caption' .. tostring(num)]
if args[ 'заголовок' .. i ] and args[ 'заголовок' .. i ] ~= '' then
        local data = mw.html.create():wikitext(args['image' .. tostring(num)])
if text ~= '' or not autoHeaders then
        if caption then
res = res .. header .. text
            data
end
                :tag('div')
header, text = _renderLine(frame, args, i), ''
                    :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()
    -- Gets the union of the header and data argument numbers,
    -- and renders them all in order using addRow.
    local rownums = union(getArgNums('header'), getArgNums('data'))
    table.sort(rownums)
    for k, num in ipairs(rownums) do
        addRow({
            header = args['header' .. tostring(num)],
            label = args['label' .. tostring(num)],
            data = args['data' .. tostring(num)],
            datastyle = args.datastyle,
            class = args['class' .. tostring(num)],
            rowclass = args['rowclass' .. tostring(num)],
            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()
    if not args.name then return end
   
    root
        :tag('tr')
            :tag('td')
                :attr('colspan', '2')
                :css('text-align', 'right')
                :wikitext(navbar{
                    args.name,
                    mini = 1,
                })
end
 
--[[
Function handles the page's title italicization.
-- If the value of "italic title" is set to "force" or "yes", titles with no parentheses () are fully italicised,
and titles which contain parentheses are italicised before the first opening parenthesis.
-- If the value of "italic title" is set to "all", the complete title, including the text in parentheses is italicized.
-- If the value of "italic_string" is entered, instead of italicizing the whole title, it will italicize only some specific text.
-- Note that if the specific text is in the disambiguation then both |italic title=all and |italic_string=<text> will need to be used.
--
-- Optionale combinations:
--- No italics.
--- Italicized page name without disambiguation.
--- Italicized complete page name, including parentheses.
--- Italicized part of the text, not including disambiguation.
--- Italicized part of the text, including parentheses.
--]]
local function renderItalicTitle()
local italicTitleModule = require("Module:Italic title")._main
local italicTitleOption = args['italic title']
local italicTitleString = args['italic_string']
 
local italicTitleArg = {}
 
if (italicTitleOption) then
local italicLowercase = mw.ustring.lower(italicTitleOption)
if (italicLowercase == "no") then
-- If set to "no" or any other disabling parameter, do nothing.
return
elseif (italicLowercase == '' or italicLowercase == 'force' or italicLowercase == 'yes') then
root:wikitext(italicTitleModule({}))
return
elseif (italicLowercase == 'all') then
italicTitleArg.all = "yes"
else
else
-- Do nothing.
text = text .. _renderLine(frame, args, i)
return
end
end
end
if text ~= '' or not autoHeaders then
res = res .. header .. text
end
end
if (italicTitleString) then
return res
italicTitleArg.string = italicTitleString
end
 
root:wikitext(italicTitleModule(italicTitleArg))
end
 
local function renderTrackingCategories()
    if args.decat ~= 'yes' then
    if args.child == 'yes' then
        if args.title then
            root:wikitext('[[Category:Pages which use embedded infobox templates with the title parameter]]')
        end
        elseif #(getArgNums('data')) == 0 and mw.title.getCurrentTitle().namespace == 0 then
            root:wikitext('[[Category:Articles which use infobox templates with no data rows]]')
        end
    end
end
 
local function _infobox()
    -- Specify the overall layout of the infobox, with special settings
    -- if the infobox is used as a 'child' inside another infobox.
    if args.child ~= 'yes' then
        root = mw.html.create('table')
       
        root
            :addClass((args.subbox ~= 'yes') and 'infobox' or nil)
            :addClass(args.bodyclass)
           
            if args.subbox == 'yes' then
                root
                    :css('padding', '0')
                    :css('border', 'none')
                    :css('margin', '-3px')
                    :css('width', 'auto')
                    :css('min-width', '100%')
                    :css('font-size', '100%')
                    :css('clear', 'none')
                    :css('float', 'none')
                    :css('background-color', 'transparent')
            else
                root
                    :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
 
local function preprocessSingleArg(argName)
    -- 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
end


local function preprocessArgs(prefixTable, step)
return p;
    -- 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('italic_string')
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;