Этот модуль составлен в 2014 году как проект новой реализации шаблона }.
Нынешняя реализация использует Модул:Infobox. Документация по использованию шаблона расположена на странице соответствующего шаблона.
Модуль развёрнут в двух вариантах: боевая версия (привязана к {{қуттӣ/модул}}, в дальнейшем планируется привязка к {{қуттӣ}}) и песочница для тестирования (привязана к {{қуттӣ/регдон2}}).
Для песочницы развёрнут модуль юнит-тестирования (запустить).
Для тестирования в боевых условиях замените в частном шаблоне-карточке {{қуттӣ}} на {{қуттӣ/модул}}.
nocat
. Внимание: при переводе шаблонов-карточек нужно заменять decat
на nocat
!заголовок_курсивом
на более привычный для раздела: italic title
пустой, yes
или force
, то заголовок выводится курсивом.заголовок_курсивом
не пустой (обычно пишется заголовок_курсивом=1
), то заголовок выводится курсивом.nocat
на более привычный для раздела: decat
установлен в yes
, то категоризация не выполняется.nocat
не пустой (обычно пишется nocat=1
), то категоризация не выполняется.scope
— польза от него сомнительна, читалки с высокой вероятностью в состоянии определить порядок чтения карточек.Используемый в коде подход гарантирует корректную работу только при шаге между подзаголовками и парами метка-текст не больше 50! В разных карточках можно встретить что-то вроде метка12=...|текст12=...|метка13=...|текст13=...|метка120=...
— такие места нужно исправлять вручную.
-- -- Модуль для реализации шаблона {{Қуттӣ}} -- local p = {} local HtmlBuilder = require('Module:HtmlBuilder') 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) .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 = HtmlBuilder.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['ном'] } })) 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 = HtmlBuilder.create('table') root .addClass('infobox') .addClass(args['синфи_бадан']) if isSet(args['зерқуттӣ']) then root .css('padding', '0') .css('border', 'none') .css('margin', '-2px') .css('width', 'auto') .css('min-width', '100%') .css('font-size', '100%') .css('clear', 'none') .css('float', 'none') .css('background-color', 'transparent') end -- Микроразметка if isSet(args['микр_бадан']) then root .attr('itemscope', 'itemscope') .attr('itemtype', args['микр_бадан']) end root .cssText(args['сабки_бадан']) renderTitle() renderAboveRow() renderAbove2Row() else root = HtmlBuilder.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 — массив таблиц, каждая из которых может содержать -- два поля: поле-строку префикса (обязательно) и поле-таблицу зависимых параметров. -- Эта функция всегда обрабатывает параметры с префиксом, но зависимые параметры -- обрабатываются, только если параметр с префиксом задан и не пустой. 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('subheaderrowstyle','сабки_зерсарлавҳа') 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