{{i}} Документація модуля[перегляд] [редагувати] [історія] [очистити кеш]

Модуль для реалізації шаблону {{Картка}}. Документація по використанню шаблону розташована на сторінці відповідного шаблону.

Тестування ред.

Поки що це тестова версія модуля. Тестовий шаблон: {{Картка1}}

І ВИКОРИСТОВУЄТЬСЯ ТІЛЬКИ ДЛЯ ТЕСТУВАННЯ!!!

Модуль заснований на російській версії модуля ru:Модуль:Карточка, що в свою чергу заснований на англійському модулі en:Module:Infobox

Що слід враховувати при експорті карток з англійської Вікіпедії ред.

  • Всі параметри переведені. Виняток становить nocat. Увага: при перекладі шаблонів-карток потрібно замінювати decat на nocat!
  • поки що в мене немає можливості внести зміни до MediaWiki:Common.css. тому на відміну від російської вікіпедії, деякі стилі поки що знаходяться в модулі.
  • Змінено спосіб обробки заголовок_курсивом на більш звичний для розділу:
    В англійській Вікіпедії якщо italic title порожній, yes або force, то заголовок виводиться курсивом.
    В перекладеній версії якщо заголовок_курсивом не порожній (зазвичай пишеться заголовок_курсивом=1), то заголовок виводиться курсивом.
  • Змінено спосіб обробки nocat на більш звичний для розділу:
    В англійській Вікіпедії якщо decat встановлений в yes, то категоризація не виконується.
    В перекладеній версії якщо nocat не порожній (зазвичай пишеться nocat=1), то категоризація не виконується.
--
-- Модуль для реалізації шаблону {{Картка}}
--

local p = {}

local HtmlBuilder2 = require('Module:HtmlBuilder2')

local args = {}
local origArgs
local argsAliases = {}
local root

local function union(t1, t2)
    -- Повертає об'єднання значень двох таблиць у вигляді послідовності.
    local vals = {}
    for k, v in pairs(t1) do
        vals[v] = true
    end
    for k, v in pairs(t2) do
        vals[v] = true
    end
    local ret = {}
    for k, v in pairs(vals) do
        table.insert(ret, k)
    end
    return ret
end

local function getArgNums(prefix)
    -- Повертає таблицю індексів існуючих полів із заданим префіксом,
    -- наприклад, для префікса 'текст' і встановлених 'текст1', 'текст2' і
    -- 'текст5' повертає {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 rowArgs.header then
        root
            .tag('tr')
                .addClass(rowArgs.rowclass)
                .attr('id', rowArgs.rowid)
                .tag('th')
                    .attr('colspan', 2)
                    .attr('id', rowArgs.headerid)
                    .addClass(rowArgs.class)
                    .addClass(args['клас_заголовків'])
                    .css('text-align', 'center')
                    .cssText(args['стиль_заголовків'])
                    .wikitext(rowArgs.header)
    elseif rowArgs.data then
        local row = root.tag('tr')
        row.addClass(rowArgs.rowclass)
        row.attr('id', rowArgs.rowid)
        if rowArgs.label then
            row
                .tag('th')
                    .attr('scope', 'row')
                    .attr('id', rowArgs.labelid)
                    .css('text-align', 'left')
                    .cssText(args['стиль_міток'])
                    .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)
            .newline()
            .wikitext(rowArgs.data)
    end
end

local function renderTitle()
    if not args['назва'] then return end

    root
        .tag('caption')
            .addClass(args['клас_назви'])
            .cssText(args['стиль_назви'])
            .wikitext(args['назва'])
end

local function renderAboveRow()
    if not args['угорі'] then return end

    root
        .tag('tr')
            .tag('th')
                .attr('colspan', 2)
                .addClass(args['клас_угорі'])
                .css('text-align', 'center')
                .css('font-size', '125%')
                .css('font-weight', 'bold')
                .cssText(args['стиль_угорі'])
                .wikitext(args['угорі'])
end

local function renderAbove2Row()
    if not args['угорі2'] then return end

    root
        .tag('tr')
            .tag('th')
                .attr('colspan', 2)
                .addClass(args['клас_угорі2'])
                .css('text-align', 'center')
                .css('font-style', 'oblique')
                .cssText(args['стиль_угорі2'])
                .wikitext(args['угорі2'])
end

local function renderBelowRow()
    if not args['внизу'] then return end

    root
        .tag('tr')
            .tag('td')
                .attr('colspan', '2')
                .addClass(args['клас_внизу'])
                .css('text-align', 'center')
                .cssText(args['стиль_внизу'])
                .newline()
                .wikitext(args['внизу'])
end

local function renderSubheaders()
    if args['підзаголовок'] then
        args['підзаголовок1'] = args['підзаголовок']
    end
    if args['клас_рядка_підзаголовка'] then
        args['клас_рядка_підзаголовка1'] = args['клас_рядка_підзаголовка']
    end
    local subheadernums = getArgNums('підзаголовок')
    for k, num in ipairs(subheadernums) do
        addRow({
            data = args['підзаголовок' .. tostring(num)],
            datastyle = args['стиль_підзаголовків'] or args['стиль_підзаголовка' .. tostring(num)],
            class = args['клас_підзаголовків'],
            rowclass = args['клас_рядка_підзаголовка' .. tostring(num)]
        })
    end
end

local function renderImages()
    if args['зображення'] then
        args['зображення1'] = args['зображення']
    end
    if args['підпис'] then
        args['підпис1'] = args['підпис']
    end
    local imagenums = getArgNums('зображення')
    for k, num in ipairs(imagenums) do
        local caption = args['підпис' .. tostring(num)]
        local data = HtmlBuilder2.create().wikitext(args['зображення' .. tostring(num)])
        if caption then
            data
                .tag('div')
                    .cssText(args['стиль_підпису'])
                    .wikitext(caption)
        end
        addRow({
            data = tostring(data),
            datastyle = args['стиль_зображення'],
            class = args['клас_зображення'],
            rowclass = args['клас_рядка_зображення' .. tostring(num)]
        })
    end
end

local function renderRows()
    -- Об'єднує індекси заголовків і текстових рядків картки,
    -- і візуалізує їх у правильному порядку через addRow.
    local rownums = union(getArgNums('заголовок'), getArgNums('текст'))
    table.sort(rownums)
    for k, num in ipairs(rownums) do
        addRow({
            header = args['заголовок' .. tostring(num)],
            label = args['мітка' .. tostring(num)],
            data = args['текст' .. tostring(num)],
            datastyle = args['стиль_тексту'],
            class = args['клас' .. tostring(num)],
            rowclass = args['клас_рядка' .. tostring(num)],
            dataid = args['id_тексту' .. tostring(num)],
            labelid = args['id_мітки' .. tostring(num)],
            headerid = args['id_заголовка' .. tostring(num)],
            rowid = args['id_рядка' .. tostring(num)]
        })
    end
end

local function renderNavBar()
    if not args['ім\'я'] then return end

    root
        .tag('tr')
            .tag('td')
                .attr('colspan', 2)
                .css('text-align', 'right')
                .wikitext(mw.getCurrentFrame():expandTemplate({ 
                    title = 'Tnavbar', 
                    args = { args['ім\'я'], mini = 1 }
                }))
end

local function isSet(x)
    -- Повертає істину, якщо x вказаний і не порожній
    -- Увага: відрізняється від enwiki! В enwiki перевіряється на рівеність 'yes'
    return x and x ~= ''
end

local function renderItalicTitle()
    -- Увага: відрізняється від enwiki! В enwiki очікується yes або force, тут працює будь-яке значення
    if isSet(args['заголовок_курсивом']) then
        root.wikitext(mw.getCurrentFrame():expandTemplate({title = 'Заголовок курсивом'}))
    end
end

local function renderTrackingCategories()
    if not isSet(args.nocat) then
        if #(getArgNums('текст')) == 0 and mw.title.getCurrentTitle().namespace == 0 then
            root.wikitext('[[Категорія:Статті з карткою без заповнених даних]]')
        end
        if isSet(args['встроєння']) and args['назва'] then
            root.wikitext('[[Категорія:Статті з вбудованою карткою і параметром назви]]')
        end
    end
end

local function _infobox()
    -- Задання загальної структури картки з додаванням стилів
    -- для карток-нащадків.
    if not isSet(args['встроєння']) then
        root = HtmlBuilder2.create('table')

        root
            .addClass('infobox')
            .addClass(args['клас_тіла'])
            .attr('cellspacing', 3)
            .css('border-spacing', '3px')

            if isSet(args['підкартка']) 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
        
        -- Мікророзмітка
        if isSet(args['мікр_тіла']) then
        	root
        	  .attr('itemscope', 'itemscope')
        	  .attr('itemtype', args['мікр_тіла'])
        end
        
        root
            .cssText(args['стиль_тіла'])

        renderTitle()
        renderAboveRow()
        renderAbove2Row()
    else
        root = HtmlBuilder2.create()

        root
            .wikitext(args['назва'])
    end

    renderSubheaders()
    renderImages() 
    renderRows() 
    renderBelowRow()  
    renderNavBar()
    renderItalicTitle()
    renderTrackingCategories()

    return tostring(root)
end

local function preprocessSingleArg(argName)
    -- Додає аргумент в таблицю аргументів, якщо він визначений і не порожній.
    -- Порожні аргументи не обробляються, як і в ParserFunctions.
    if origArgs[argName] and origArgs[argName] ~= '' then
        args[argName] = origArgs[argName]
    end
end

local function translateArg(aliasArgName,localArgName)
	-- Функція додає підтримку аліасів параметрів (наприклад, іншою мовою)
	
	-- Додаєм аліас параметра в таблицю аліасів
	-- Для одного параметра може бути кілька аліасів
	-- Нумеровані параметри(текст1 і т.д.) заносяться без номера
	if not 	argsAliases[localArgName] then
		argsAliases[localArgName] = {}
	end
	table.insert(argsAliases[localArgName], aliasArgName)
	
	-- Пока для тестування: значення аліасів додаются в таблицю аргументів
	-- Нумеровані параметри не будуть працювати
    if origArgs[localArgName] and origArgs[localArgName] ~= '' then
    	-- параметр вже задан на локальній мові
    else
    	-- якщо аліас заданий і не пустий
	    if origArgs[aliasArgName] and origArgs[aliasArgName] ~= '' then
	        origArgs[localArgName] = origArgs[aliasArgName]
	    end
    end
end

local function preprocessArgs(prefixTable, step)
    -- Зберігає параметри з заданими префіксами в таблицю args, послідовно обходячи 
    -- аргументи в потрібному порядку і з потрібним кроком. Завдяки цьому виноски та ін. з'являються
    -- в правильному порядку. prefixTable — масив таблиць, кожна з яких може містити
    -- два поля: a "prefix" string and a "depend" table. The function always parses
    -- Ця функція завжди обробляє параметри з префіксом, але залежні параметри
    -- обробляються, тільки якщо параметр з префіксом заданий і не порожній.
    if type(prefixTable) ~= 'table' then
        error("В якості таблиці префіксів повинна використовуватися таблиця", 2)
    end
    if type(step) ~= 'number' then
        error("Неприпустимий тип параметра кроку", 2)
    end

    -- Перевірка правильності даних та обробка параметрів без суфіксів.
    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('Неприпустима таблиця префіксів preprocessArgs', 2)
        end
        preprocessSingleArg(v.prefix)
        -- Залежні параметри обробляються, тільки якщо параметр з префіксом заданий і не порожній.
        if args[v.prefix] and v.depend then
            for j, dependValue in ipairs(v.depend) do
                if type(dependValue) ~= 'string' then
                    error('Неприпустимий тип залежного параметра в таблиці preprocessArgs')
                end
                preprocessSingleArg(dependValue)
            end
        end
    end

    -- Обхід нумерованих аргументів.
    local a = 1 -- Змінна-лічильник.
    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 -- Шукати аргументи далі, якщо був хоча б один (в т. ч. порожній)
                    preprocessSingleArg(prefixArgName)
                end
                -- Обробляємо залежні аргументи, якщо визначена таблиця залежностей,
                -- а також вказаний не порожній аргумент з префіксом, або обробляється
                -- "префікс1" і "префікс" заданий (наприклад, "зображення1" являється синонімом для "зображення").
                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)
    -- При запуску через #invoke аргументи передаються через стандартну систему.
    -- При тестуванні також можна передавати таблицю аргументів через frame.
    if frame == mw.getCurrentFrame() then
        origArgs = frame:getParent().args
    else
        origArgs = frame
    end
 
    -- Підтримка параметрів з англовікі
    translateArg('child','встроєння')
    translateArg('bodyclass','клас_тіла')
    translateArg('subbox','підкартка')
    translateArg('bodystyle','стиль_тіла')
    translateArg('title','назва')
    translateArg('titleclass','клас_назви')
    translateArg('titlestyle','стиль_назви')
    translateArg('above','угорі')
    translateArg('aboveclass','клас_угорі')
    translateArg('abovestyle','стиль_угорі')

    translateArg('subheader','підзаголовок')
    translateArg('subheaderstyle','стиль_підзаголовка')
    translateArg('subheaderrowclass','клас_підзаголовка')

    translateArg('subheaderstyle','стиль_підзаголовків')
    translateArg('subheaderclass','клас_підзаголовків')


    translateArg('image','зображення')
    translateArg('caption','підпис')
    translateArg('imagerowclass','клас_рядка_зображення')

    translateArg('captionstyle','стиль_підпису')
    translateArg('imagestyle','стиль_зображення')
    translateArg('imageclass','клас_зображення')
    

    translateArg('header','заголовок')
    translateArg('data','текст')
    translateArg('label','мітка')
    translateArg('rowclass','клас_рядка')
    translateArg('class','клас')
    translateArg('dataid','id_тексту')
    translateArg('labelid','id_мітки')
    translateArg('headerid','id_заголовка')
    translateArg('rowid','id_рядка')

    translateArg('headerclass','клас_заголовків')
    translateArg('headerstyle','стиль_заголовків')
    translateArg('labelstyle','стиль_міток')
    translateArg('datastyle','стиль_тексту')
    translateArg('below','внизу')
    translateArg('belowclass','клас_внизу')
    translateArg('belowstyle','стиль_внизу')
    translateArg('name','ім\'я')
    --translateArg('italic title','заголовок_курсивом')
    --translateArg('','')
    

    -- Параметри обробляються в напрямку читання картки, щоб
    -- виноски та ін. відображалися в потрібних місцях. Параметри, що залежать 
    -- від інших параметрів, обробляються тільки за наявності інших параметрів,
    -- щоб у списку виносок не виникали небажані виноски.
    preprocessSingleArg('встроєння')
    preprocessSingleArg('клас_тіла')
    preprocessSingleArg('підкартка')
    preprocessSingleArg('стиль_тіла')
    preprocessSingleArg('назва')
    preprocessSingleArg('клас_назви')
    preprocessSingleArg('стиль_назви')
    preprocessSingleArg('угорі')
    preprocessSingleArg('клас_угорі')
    preprocessSingleArg('стиль_угорі')
    preprocessSingleArg('угорі2')
    preprocessSingleArg('клас_угорі2')
    preprocessSingleArg('стиль_угорі2')
    preprocessArgs({
        {prefix = 'підзаголовок', depend = {'стиль_підзаголовка', 'клас_підзаголовка'}}
    }, 10)
    preprocessSingleArg('стиль_підзаголовків')
    preprocessSingleArg('клас_підзаголовків')
    preprocessArgs({
        {prefix = 'зображення', depend = {'підпис', 'клас_рядка_зображення'}}
    }, 10)
    preprocessSingleArg('стиль_підпису')
    preprocessSingleArg('стиль_зображення')
    preprocessSingleArg('клас_зображення')
    preprocessArgs({
        {prefix = 'заголовок'},
        {prefix = 'текст', depend = {'мітка'}},
        {prefix = 'клас_рядка'},
        {prefix = 'клас'},
        {prefix = 'id_тексту'},
        {prefix = 'id_мітки'},
        {prefix = 'id_заголовка'},
        {prefix = 'id_рядка'}
    }, 50)
    preprocessSingleArg('клас_заголовків')
    preprocessSingleArg('стиль_заголовків')
    preprocessSingleArg('стиль_міток')
    preprocessSingleArg('стиль_тексту')
    preprocessSingleArg('внизу')
    preprocessSingleArg('клас_внизу')
    preprocessSingleArg('стиль_внизу')
    preprocessSingleArg('ім\'я')
    preprocessSingleArg('заголовок_курсивом')
    preprocessSingleArg('nocat')

    return _infobox()
end

return p