Модуль:Карточка
Внешний вид
Для документации этого модуля может быть создана страница Модуль:Карточка/doc
--[[
Модуль:Карточка — отрисовка карточки для любого типа сущности, кроме
персоны. У персоны своя логика (частичные даты, годы до нашей эры,
склонение месяцев), она осталась в Модуль:Персона.
Здесь общее для организаций, терминов, произведений, событий и мест:
собрать пары «подпись — значение», выбросить пустые, разбить списки по
точке с запятой, обрезать длинные и не рисовать таблицу, если показывать
нечего. Пустая карточка хуже отсутствующей: она обещает сведения, которых
нет.
Шаблон своего типа остаётся тонким: он объявляет поля, зовёт
{{Сущность}} для общей записи и передаёт сюда готовый список строк.
Разделитель списков — точка с запятой, как во всём проекте.
]]
local p = {}
--- Сколько значений списка показываем; остальное сворачиваем в «и ещё N».
local LIMIT = 5
local function trim( s )
return ( tostring( s or '' ):gsub( '^%s*(.-)%s*$', '%1' ) )
end
--- Разбивает список по точке с запятой. Запятая внутри значения
--- («Ростов-на-Дону, Россия») разбор не ломает — это и есть причина выбора.
local function split( value )
local out = {}
for part in tostring( value ):gmatch( '[^;]+' ) do
local item = trim( part )
if item ~= '' then
out[#out + 1] = item
end
end
return out
end
--- Дата в записи «1809-08-16» — не то, что читают. Разбор и склонение
--- месяцев живут в Модуль:Персона вместе с правилами о неполных датах и о
--- годах до нашей эры; заводить здесь второй разбор значило бы обречь их
--- разойтись. Организация, событие и произведение показывали сырую запись.
local persona = require( 'Модуль:Персона' )
--- Похоже ли значение на дату ISO. Проверяем перед вызовом, чтобы «1809»
--- в поле «тираж» не превратилось в год: форматируем только то, что
--- записано датой целиком.
local function looksLikeDate( value )
return value:match( '^%d%d%d%d%-%d%d%-%d%d$' )
or value:match( '^%d%d%d%d%-%d%d$' )
or value:match( '^%-%d%d%d%d%-%d%d%-%d%d$' )
end
--- Значение строки: одиночное показываем как есть, список — через запятую с
--- обрезкой. Обрезка нужна, чтобы карточка не превращалась в простыню:
--- полный список всегда есть в тексте статьи.
local function renderValue( value )
local items = split( value )
if #items <= 1 then
local one = trim( value )
if looksLikeDate( one ) then
return persona.formatDate( one ) or one
end
return one
end
if #items <= LIMIT then
return table.concat( items, ', ' )
end
local shown = {}
for i = 1, LIMIT do
shown[i] = items[i]
end
return table.concat( shown, ', ' ) .. ' и ещё ' .. ( #items - LIMIT )
end
--[[
Точка входа. Именованные аргументы:
заголовок — подпись карточки
подзаголовок — строка под заголовком
изображение — имя файла без «Файл:»
подпись_изображения
лицензия_подтверждена — «да» разрешает показ изображения
Строки задаются парами «строка1_подпись» / «строка1_значение» и так далее,
до строка20. Порядок задаёт шаблон типа: он знает, что важно для своего
типа, а модуль не должен об этом догадываться.
]]
p['карточка'] = function ( frame )
local args = frame.args
local rows = {}
for i = 1, 20 do
local label = trim( args['строка' .. i .. '_подпись'] )
local value = trim( args['строка' .. i .. '_значение'] )
if label ~= '' and value ~= '' then
rows[#rows + 1] = { label = label, value = renderValue( value ) }
end
end
local image = trim( args['изображение'] )
-- Изображение без подтверждённой лицензии не показывается никогда.
-- Это правило проекта, а не настройка оформления.
local licensed = trim( args['лицензия_подтверждена'] ):lower()
local showImage = image ~= '' and ( licensed == 'да' or licensed == 'yes' )
if #rows == 0 and not showImage then
return ''
end
local root = mw.html.create( 'table' )
root:addClass( 'pw-card' )
local title = trim( args['заголовок'] )
if title ~= '' then
local caption = root:tag( 'caption' ):addClass( 'pw-card__title' )
caption:wikitext( title )
local sub = trim( args['подзаголовок'] )
if sub ~= '' then
caption:tag( 'div' ):addClass( 'pw-card__subtitle' ):wikitext( sub )
end
end
if showImage then
local cell = root:tag( 'tr' ):tag( 'td' )
:attr( 'colspan', 2 ):addClass( 'pw-card__image' )
cell:wikitext( '[[Файл:' .. image .. '|frameless|260px|'
.. ( trim( args['подпись_изображения'] ) ~= ''
and trim( args['подпись_изображения'] ) or title ) .. ']]' )
local caption = trim( args['подпись_изображения'] )
if caption ~= '' then
cell:tag( 'div' ):addClass( 'pw-card__caption' ):wikitext( caption )
end
end
for _, row in ipairs( rows ) do
local tr = root:tag( 'tr' )
tr:tag( 'th' ):attr( 'scope', 'row' ):wikitext( row.label )
tr:tag( 'td' ):wikitext( row.value )
end
return tostring( root )
end
-- Точки входа названы по-русски, поэтому объявлены через скобки: имена в Lua
-- состоят только из ASCII, и «function p.карточка()» не разбирается вовсе.
return p