Модуль:Рецепт
Внешний вид
Для документации этого модуля может быть создана страница Модуль:Рецепт/doc
-- Module:RecipeBox
-- Инфоблок рецепта: изображение, таблица свойств, ссылки на статью в Википедии и Викискладе,
-- автоматические категории и пиктограмма сложности.
-- Приоритет данных: параметр шаблона > Wikidata.
local p = {}
--------------------------------------------------------------------
-- Свойства Wikidata (для fallback)
--------------------------------------------------------------------
local propertyMap = {
image = 'P18', -- изображение
category = 'P8431', -- тип блюда
cuisine = 'P2012', -- кухня
ingredients = 'P527', -- состав
}
--------------------------------------------------------------------
-- Алиасы параметров (русские и позиционные)
--------------------------------------------------------------------
local paramAlias = {
['Изображение']='image',['5']='image',
['Категория']='category',['1']='category',
['Кухня']='cuisine',['7']='cuisine',
['Порций']='portions',
['Время']='time',
['Сложность']='difficulty',['4']='difficulty',
['Энергетическая ценность']='calories',
['Ингредиенты']='ingredients',['8']='ingredients',
['Википедия']='wikiparam',['9']='wikiparam',
['Викисклад']='commonsparam',['10']='commonsparam',
}
--------------------------------------------------------------------
-- Константы отображения
--------------------------------------------------------------------
local fields = {'category','cuisine','ingredients', 'portions','time','difficulty','calories'}
local catFields = { category=true, cuisine=true, ingredients=true }
local linkFields = { category=true, cuisine=true, ingredients=true }
local labelMap = {
category='Категория:', cuisine='Кухня:', portions='Порций:', time='Время:',
difficulty='Сложность:', calories='Энергетическая ценность:', ingredients='Ингредиенты:'
}
local noFallback = { portions=true, time=true, difficulty=true, calories=true }
--------------------------------------------------------------------
-- Кэш меток Wikidata
--------------------------------------------------------------------
local labelCache = {}
local function wdLabel(id)
if not id then return '' end
if labelCache[id] then return labelCache[id] end
local lbl = mw.wikibase.getLabel(id) or id
labelCache[id] = lbl
return lbl
end
--------------------------------------------------------------------
-- Datavalue → строка
--------------------------------------------------------------------
local function parseDV(dv)
if not dv then return nil end
if dv.id then return wdLabel(dv.id) end
if dv[1] and dv[1].id then
local t = {}
for _, itm in ipairs(dv) do t[#t+1] = wdLabel(itm.id) end
return table.concat(t, ', ')
end
if type(dv)=='string' then return dv end
if dv.amount then return dv.amount end
if dv.time then return dv.time end
if dv.text then return dv.text end
return nil
end
local function getAllWD(entity, pid)
local claims = entity and entity.claims and entity.claims[pid]
if not claims then return nil end
local seen, out = {}, {}
for _, cl in ipairs(claims) do
local v = parseDV(cl.mainsnak.datavalue and cl.mainsnak.datavalue.value)
if v and v~='' and not seen[v] then seen[v]=true; out[#out+1]=v end
end
if #out==0 then return nil end
return table.concat(out, '<br/>')
end
--------------------------------------------------------------------
-- Ссылки на категории внутри таблицы
--------------------------------------------------------------------
local function makeCategoryLinks(raw)
local parts = mw.text.split(raw, '<br/>')
for i, part in ipairs(parts) do
part = mw.text.trim(part)
if part~='' and not part:match('%[%[') then
parts[i] = '[[:Категория:'..part..'|'..part..']]'
else
parts[i] = part
end
end
return table.concat(parts, '<br/>')
end
--------------------------------------------------------------------
-- Пиктограммы сложности
--------------------------------------------------------------------
local diffInfo={ ['1']={label='Очень простой',cat='Очень простой'}, ['2']={label='Простой',cat='Простой'}, ['3']={label='Средняя',cat='Средней сложности'}, ['4']={label='Сложная',cat='Сложный'}, ['5']={label='Очень сложный',cat='Очень сложный'} }
local function diffMarkup(v)
local key = tostring(v):match('^%s*(%d)')
local d = diffInfo[key]
if not d then return v end
return '[[File:'..key..'o5dots.svg|48px|'..d.label..'|link=Категория:'..d.cat..' рецепт]]'
end
--------------------------------------------------------------------
-- Изображение
--------------------------------------------------------------------
local function getImage(args, entity)
if args.image and args.image~='' then return mw.text.trim(args.image) end
local cl = entity and entity.claims and entity.claims[propertyMap.image]
if cl and cl[1] and type(cl[1].mainsnak.datavalue.value)=='string' then
return cl[1].mainsnak.datavalue.value
end
return ''
end
--------------------------------------------------------------------
-- Ссылка на Википедию (param > WD) с защитой при отсутствии entity
--------------------------------------------------------------------
local function getWikiParam(args)
return args.wikiparam and mw.text.trim(args.wikiparam) or ''
end
local function getWikipediaLink(entity, args)
local custom = getWikiParam(args)
if custom~='' then
return '[[File:Wikipedia-w.svg|14px]] [[w:'..custom..'|'..custom..']] в Википедии'
end
if not (entity and entity.id) then return nil end
local link = mw.wikibase.getSitelink(entity.id, 'ruwiki')
if link and link~='' then
return '[[File:Wikipedia-w.svg|14px]] [[:w:'..link..'|'..link..']] в Википедии'
end
return nil
end
--------------------------------------------------------------------
-- Ссылка на Викисклад (param > WD) с защитой
--------------------------------------------------------------------
local function getCommonsParam(args)
return args.commonsparam and mw.text.trim(args.commonsparam) or ''
end
local function getCommonsLink(entity, args)
local custom = getCommonsParam(args)
if custom~='' then
return '[[File:Commons-logo.svg|14px]] [[c:'..custom..'|'..custom..']] в Викискладе'
end
if not (entity and entity.id) then return nil end
local link = mw.wikibase.getSitelink(entity.id, 'commonswiki')
if link and link~='' then
return '[[File:Commons-logo.svg|14px]] [[:commons:'..link..'|'..link..']] в Викискладе'
end
return nil
end
--------------------------------------------------------------------
-- Основная функция
--------------------------------------------------------------------
function p.Reciepe(frame)
-- Normalize args
local raw = frame:getParent().args or {}
local args = {}
for k, v in pairs(raw) do
local key = paramAlias[k] or string.lower(k)
local trimmed = mw.text.trim(v)
if catFields[key] and trimmed~='' then
trimmed = string.lower(trimmed)
end
args[key] = trimmed
end
local entity = mw.wikibase.getEntityObject() or {}
local out, present, catBuffer = {}, {}, {}
-- Image
local img = getImage(args, entity)
present.image = (img~='')
if present.image then
out[#out+1] = '<div class="image">[[File:'..img..'|300px]]</div>'
out[#out+1] = '<hr style="width:100%; margin:4px 0; border:none; border-top:1px solid #ccc;" />'
end
-- Table and collect categories
out[#out+1] = '<table style="width:100%;">'
for _, field in ipairs(fields) do
local val = args[field] or ''
if val=='' and not noFallback[field] then
val = getAllWD(entity, propertyMap[field]) or ''
end
present[field] = (val~='')
if present[field] then
if field=='difficulty' then
val = diffMarkup(val)
else
if catFields[field] then
local plain = val:gsub('<br/>',',')
for _, item in ipairs(mw.text.split(plain, ',%s*')) do
item = mw.text.trim(item)
if item~='' then catBuffer['[[Категория:'..item..']]'] = true end
end
end
val = val:gsub(',%s*','<br/>')
if linkFields[field] then val = makeCategoryLinks(val) end
end
local label = labelMap[field] or (field..':')
out[#out+1] = '<tr><td style="vertical-align:top;text-align:left;">'..label..'</td><td style="vertical-align:top;">'..val..'</td></tr>'
end
end
out[#out+1] = '</table>'
-- Wikipedia link
local wlink = getWikipediaLink(entity, args)
if wlink then
out[#out+1] = '<hr style="width:100%; margin:4px 0; border:none; border-top:1px solid #ccc;" />'
out[#out+1] = '<div style="text-align:center;">'..wlink..'</div>'
end
-- Commons link
local clink = getCommonsLink(entity, args)
if clink then
out[#out+1] = '<div style="text-align:center;">'..clink..'</div>'
end
-- Technical categories
if not present.image then catBuffer['[[Категория:Рецепты без иллюстраций]]'] = true end
if not present.category then catBuffer['[[Категория:Рецепты без категории]]'] = true end
if not present.cuisine then catBuffer['[[Категория:Рецепты без кухни]]'] = true end
if not present.ingredients then catBuffer['[[Категория:Рецепты без ингредиентов]]'] = true end
-- Add collected categories
for cat,_ in pairs(catBuffer) do out[#out+1] = cat end
return table.concat(out, '\n')
end
return p