Module:Recipe: Difference between revisions
Appearance
Replacing with my custom version from ZZZ, because it's better here. |
No edit summary |
||
| Line 1: | Line 1: | ||
local p = {} | local p = {} | ||
local Card = require('Module:Card') | local Card = require('Module:Card') | ||
--Arguments for template | -- Arguments for template | ||
local param = { | local param = { | ||
sCharArg = 'character', | sCharArg = 'character', | ||
sTypeArg = 'type', | sTypeArg = 'type', | ||
sSortArg = 'sort', | sSortArg = 'sort', | ||
sSortDelim = ';', --Needs to be pattern | sSortDelim = ';', -- Needs to be pattern-safe for current usage | ||
sSortDelim2 = '¤', | sSortDelim2 = '¤', | ||
sTimeArg = 'time', | sTimeArg = 'time', | ||
| Line 14: | Line 14: | ||
sPage = 'page' | sPage = 'page' | ||
} | } | ||
p.param = param | p.param = param | ||
function padLeft(str, amt) | local function padLeft(str, amt) | ||
str = tostring(str or '') | |||
return string.rep('0', math.max(amt - str:len(), 0)) .. str | |||
end | |||
local function pluralize(sOut, plural) | |||
if plural then | |||
sOut = sOut .. 's' | |||
end | |||
return sOut | |||
end | |||
local function normalizeType(s) | |||
return mw.ustring.lower(mw.text.trim(tostring(s or ''))) | |||
end | |||
local function argExists(args, key) | |||
return args[key] ~= nil and tostring(args[key]) ~= '' | |||
end | end | ||
function addRecipe(sAmt, sName) | local function addRecipe(category, sAmt, sName) | ||
local cardNode = Card._main({ | local cardNode = Card._main({ | ||
name = sName, | name = sName, | ||
| Line 27: | Line 44: | ||
mobile = 'bulleted' | mobile = 'bulleted' | ||
}) | }) | ||
category:wikitext('[[Category:Uses ', sName, '|', padLeft(sAmt:gsub('%D', ''), 10), ']]') | |||
category:wikitext( | |||
'[[Category:Uses ', | |||
sName, | |||
'|', | |||
padLeft(tostring(sAmt or ''):gsub('%D', ''), 10), | |||
']]' | |||
) | |||
return cardNode | return cardNode | ||
end | end | ||
function | local function addSimpleCard(sName, sText) | ||
return Card._main({ | |||
name = sName, | |||
text = sText, | |||
show_caption = '1', | |||
mobile = 'bulleted' | |||
}) | |||
end | end | ||
function | local function renderHeader(args, output, category) | ||
local | local header = output:tag('div'):addClass('recipe_header') | ||
local sType = args[param.sTypeArg] | |||
return | header:tag('span'):addClass('recipe_header_main') | ||
-- Mobile Icon/Text, preserved from original | |||
:tag('span'):addClass('mobileHide'):wikitext('<big>' .. sType .. '</big>'):done() | |||
-- Desktop Icon/Text, preserved from original | |||
:tag('span'):addClass('mobileHide'):wikitext('<big>' .. sType .. '</big>'):done() | |||
-- Text | |||
:tag('span'):addClass('recipe_header_text'):wikitext('[[' .. sType .. ']]'):done() | |||
category:wikitext('[[Category:' .. sType .. ']]') | |||
return header | |||
end | end | ||
function | local function renderTime(args, header) | ||
if type(args[param.sTimeArg]) ~= 'string' then | |||
return | |||
if type(args[param. | end | ||
local tTime = {} | |||
local key = false | |||
local plural = false | |||
for n1, d, n2, h, n3, m, n4, s in mw.ustring.gmatch( | |||
args[param.sTimeArg], | |||
'(%d+)(d?)(%d*)(h?)(%d*)(m?)(%d*)(s?)' | |||
) do | |||
table.insert(tTime, n1) | |||
if n1 ~= '1' then | |||
plural = true | |||
end | |||
if d == 'd' then | |||
table.insert(tTime, pluralize('day', plural)) | |||
plural = false | |||
key = true | |||
end | |||
if n2 ~= '' then | |||
table.insert(tTime, n2) | |||
if n2 ~= '1' then | |||
plural = true | |||
end | end | ||
end | |||
if h == 'h' then | |||
table.insert(tTime, pluralize('hour', plural)) | |||
plural = false | |||
key = true | |||
end | |||
if n3 ~= '' then | |||
table.insert(tTime, n3) | |||
if n3 ~= '1' then | |||
plural = true | |||
end | end | ||
end | |||
if m == 'm' then | |||
table.insert(tTime, pluralize('minute', plural)) | |||
plural = false | |||
key = true | |||
end | |||
if n4 ~= '' then | |||
table.insert(tTime, n4) | |||
if n4 ~= '1' then | |||
plural = true | |||
end | end | ||
end | end | ||
if | if s == 's' then | ||
table.insert(tTime, pluralize('second', plural)) | |||
key = true | |||
end | end | ||
end | |||
if not key then | |||
table.insert(tTime, pluralize('minute', plural)) | |||
end | |||
local sTime = '' | |||
for _, each in ipairs(tTime) do | |||
sTime = sTime .. each .. ' ' | |||
end | |||
header:tag('span'):addClass('recipe_header_sub') | |||
:tag('span'):addClass('mobileHide'):wikitext(' for '):done() | |||
:tag('span'):addClass('hidden'):wikitext(' for '):done() | |||
:tag('span'):addClass('recipe_header_text'):wikitext(sTime):done() | |||
end | |||
local function renderCharacter(args, header) | |||
if type(args[param.sCharArg]) ~= 'string' then | |||
return | |||
end | |||
local sCharName = args[param.sCharArg] | |||
header:tag('span'):addClass('recipe_header_sub') | |||
:tag('span'):addClass('mobileHide'):wikitext(' with '):done() | |||
:tag('span'):addClass('hidden'):wikitext('[[File:' .. sCharName .. ' Icon.png|24x24px|link=' .. sCharName .. ']]'):done() | |||
:tag('span'):addClass('recipe_header_text'):wikitext('[[' .. sCharName .. ']]'):done() | |||
end | |||
local function renderYield(args, body) | |||
if args[param.sYieldArg] == '0' then | |||
return | |||
end | |||
local sYield = args[param.sYieldArg] or '1' | |||
local pageTitle = args.page or mw.title.getCurrentTitle().text | |||
local yieldCard = Card._main({ | |||
name = pageTitle, | |||
text = sYield, | |||
show_caption = '1', | |||
}) | |||
body | |||
:tag('div'):addClass('recipe_body_icon') | |||
:wikitext('➜'):done() | |||
:tag('div'):addClass('recipe_body_yield') | |||
:node(yieldCard) | |||
-- Preserved from original, though unused. | |||
local itemText = require('Module:Item').main{ | |||
[1] = pageTitle, | |||
[2] = '15', | |||
x = sYield | |||
} | |||
end | |||
-------------------------------------------------------------------------------- | |||
-- Standard, non-cooking recipe rendering | |||
-------------------------------------------------------------------------------- | |||
local function renderStandardRecipe(args, frame, output, category) | |||
local tArgsProcessed = {} | |||
local header = renderHeader(args, output, category) | |||
renderTime(args, header) | |||
renderCharacter(args, header) | |||
local body = output:tag('div'):addClass('recipe_body') | |||
local sSortDelim = param.sSortDelim | |||
-- Check if sSortDelim2 exists in sSortArg. | |||
if ((args[param.sSortArg] or ''):find(param.sSortDelim2) ~= nil) then | |||
sSortDelim = param.sSortDelim2 | |||
end | |||
-- Process Sort Parameter, split by delimiter. | |||
for sKey in string.gmatch(args[param.sSortArg] or '', '([^' .. sSortDelim .. ']+)') do | |||
if type(args[sKey]) ~= 'nil' then | |||
body:node(addRecipe(category, args[sKey], sKey)) | |||
tArgsProcessed[sKey] = true | |||
end | |||
end | |||
-- Process rest of unrestricted parameters. | |||
for sKey, sVal in pairs(args) do | |||
local restricted = false | |||
for _, keyParam in pairs(param) do | |||
if keyParam == sKey then | |||
restricted = true | |||
end | end | ||
end | end | ||
-- | if tArgsProcessed[sKey] ~= true and not restricted then | ||
body:node(addRecipe(category, sVal, sKey)) | |||
end | |||
end | |||
for _, | |||
renderYield(args, body) | |||
body:done() | |||
end | |||
if | -------------------------------------------------------------------------------- | ||
-- Cooking recipe rendering | |||
-------------------------------------------------------------------------------- | |||
local function getCookingIngredient(args, index) | |||
local prefix = 'item_' .. index | |||
local ingredient = { | |||
index = index, | |||
amount = args[prefix .. '_amount'] or '1', | |||
quality = args[prefix .. '_quality'], | |||
item = args[prefix], | |||
types = {}, | |||
options = {} | |||
} | |||
-- Single type: | |||
-- |item_1_type = Fish | |||
if argExists(args, prefix .. '_type') then | |||
table.insert(ingredient.types, args[prefix .. '_type']) | |||
end | |||
-- Multiple types: | |||
-- |item_1_type_1 = Freshwater Fish | |||
-- |item_1_type_2 = Saltwater Fish | |||
local typeIndex = 1 | |||
while argExists(args, prefix .. '_type_' .. typeIndex) do | |||
table.insert(ingredient.types, args[prefix .. '_type_' .. typeIndex]) | |||
typeIndex = typeIndex + 1 | |||
end | |||
-- Multiple accepted specific items: | |||
-- |item_1_option_1 = Rice | |||
-- |item_1_option_2 = Wheat | |||
local optionIndex = 1 | |||
while argExists(args, prefix .. '_option_' .. optionIndex) do | |||
table.insert(ingredient.options, args[prefix .. '_option_' .. optionIndex]) | |||
optionIndex = optionIndex + 1 | |||
end | |||
local hasIngredient = | |||
ingredient.item ~= nil | |||
or #ingredient.types > 0 | |||
or #ingredient.options > 0 | |||
if not hasIngredient then | |||
return nil | |||
end | |||
return ingredient | |||
end | |||
local function getKitchenware(args) | |||
local kitchenware = {} | |||
-- Single kitchenware: | |||
-- |kitchenware = Cooking Pot | |||
if argExists(args, 'kitchenware') then | |||
table.insert(kitchenware, args.kitchenware) | |||
end | |||
-- Multiple kitchenware: | |||
-- |kitchenware_1 = Cooking Pot | |||
-- |kitchenware_2 = Frying Pan | |||
local index = 1 | |||
while argExists(args, 'kitchenware_' .. index) do | |||
table.insert(kitchenware, args['kitchenware_' .. index]) | |||
index = index + 1 | |||
end | |||
return kitchenware | |||
end | |||
local function renderCookingTypeRequirement(category, typeBox, amountText, types) | |||
if #types == 1 then | |||
local typeName = types[1] | |||
typeBox:tag('div') | |||
:addClass('recipe_body_cooking_requirement') | |||
:wikitext(amountText .. ' of [[:Category:' .. typeName .. '|' .. typeName .. ']]') | |||
category:wikitext('[[Category:Uses ', typeName, ']]') | |||
return | |||
end | |||
typeBox:tag('div') | |||
:addClass('recipe_body_cooking_requirement') | |||
:wikitext(amountText .. ' of any of:') | |||
for _, typeName in ipairs(types) do | |||
typeBox:tag('div') | |||
:addClass('recipe_body_cooking_type') | |||
:wikitext('[[:Category:' .. typeName .. '|' .. typeName .. ']]') | |||
category:wikitext('[[Category:Uses ', typeName, ']]') | |||
end | |||
end | |||
local function renderCookingIngredient(category, body, ingredient) | |||
local wrapper = body:tag('div') | |||
:addClass('recipe_body_cooking_ingredient') | |||
local amountText = tostring(ingredient.amount or '1') | |||
if ingredient.quality then | |||
amountText = amountText .. ' ' .. ingredient.quality | |||
end | |||
-- Specific item: | |||
-- |item_1 = Rice | |||
if ingredient.item then | |||
wrapper:node(addRecipe(category, amountText, ingredient.item)) | |||
return | |||
end | |||
-- Multiple specific item options: | |||
-- |item_1_option_1 = Rice | |||
-- |item_1_option_2 = Wheat | |||
if #ingredient.options > 0 then | |||
local optionBox = wrapper:tag('div') | |||
:addClass('recipe_body_cooking_options') | |||
optionBox:tag('div') | |||
:addClass('recipe_body_cooking_requirement') | |||
:wikitext(amountText .. ' of any of:') | |||
for _, itemName in ipairs(ingredient.options) do | |||
optionBox:node(addRecipe(category, '', itemName)) | |||
end | |||
return | |||
end | |||
-- Type-based ingredient: | |||
-- |item_1_type = Fish | |||
-- or: | |||
-- |item_1_type_1 = Freshwater Fish | |||
-- |item_1_type_2 = Saltwater Fish | |||
if #ingredient.types > 0 then | |||
local typeBox = wrapper:tag('div') | |||
:addClass('recipe_body_cooking_types') | |||
renderCookingTypeRequirement(category, typeBox, amountText, ingredient.types) | |||
return | |||
end | |||
end | |||
local function renderKitchenware(category, body, args) | |||
local kitchenware = getKitchenware(args) | |||
if #kitchenware == 0 then | |||
return | |||
end | |||
local wrapper = body:tag('div') | |||
:addClass('recipe_body_kitchenware') | |||
wrapper:tag('div') | |||
:addClass('recipe_body_kitchenware_label') | |||
:wikitext('Kitchenware') | |||
for _, itemName in ipairs(kitchenware) do | |||
wrapper:node(addSimpleCard(itemName, '')) | |||
category:wikitext('[[Category:Uses ', itemName, ']]') | |||
end | |||
end | |||
local function renderCookingRecipe(args, frame, output, category) | |||
local header = renderHeader(args, output, category) | |||
renderTime(args, header) | |||
renderCharacter(args, header) | |||
local body = output:tag('div') | |||
:addClass('recipe_body') | |||
:addClass('recipe_body_cooking') | |||
local ingredientIndex = 1 | |||
local foundIngredient = false | |||
while true do | |||
local ingredient = getCookingIngredient(args, ingredientIndex) | |||
if not ingredient then | |||
break | |||
end | end | ||
foundIngredient = true | |||
if | renderCookingIngredient(category, body, ingredient) | ||
ingredientIndex = ingredientIndex + 1 | |||
end | |||
if not foundIngredient then | |||
body:tag('span') | |||
:addClass('error') | |||
:wikitext('Cooking recipe error. No cooking ingredients found.') | |||
end | |||
renderKitchenware(category, body, args) | |||
renderYield(args, body) | |||
body:done() | |||
end | |||
-------------------------------------------------------------------------------- | |||
-- Entry points | |||
-------------------------------------------------------------------------------- | |||
function p.main(frame) | |||
local args = require('Module:Arguments').getArgs(frame, { | |||
parentFirst = true, | |||
wrapper = { 'Template:Recipe' } | |||
}) | |||
return p._main(args, frame) | |||
end | |||
function p._main(args, frame) | |||
local output = mw.html.create('div') | |||
:addClass('recipe_container') | |||
-- Important: category must be local to this render. | |||
-- Do not keep it as a module-level variable. | |||
local category = mw.html.create() | |||
if type(args[param.sTypeArg]) ~= 'string' then | |||
output:tag('span') | |||
:addClass('error') | |||
:wikitext('Recipe type error. Must include recipe type.') | |||
else | |||
local sType = args[param.sTypeArg] | |||
if normalizeType(sType) == 'cooking' then | |||
renderCookingRecipe(args, frame, output, category) | |||
else | |||
renderStandardRecipe(args, frame, output, category) | |||
end | end | ||
end | end | ||
output:node(require('Module:Namespace detect').main{["main"]=category}) | |||
output:node(require('Module:Namespace detect').main({ | |||
["main"] = category | |||
})) | |||
return output | return output | ||
end | end | ||
return p | return p | ||
Revision as of 07:29, 7 May 2026
| Main | Documentation | Usage |
Lua module for {{Recipe}}.
local p = {}
local Card = require('Module:Card')
-- Arguments for template
local param = {
sCharArg = 'character',
sTypeArg = 'type',
sSortArg = 'sort',
sSortDelim = ';', -- Needs to be pattern-safe for current usage
sSortDelim2 = '¤',
sTimeArg = 'time',
sYieldArg = 'yield',
sPage = 'page'
}
p.param = param
local function padLeft(str, amt)
str = tostring(str or '')
return string.rep('0', math.max(amt - str:len(), 0)) .. str
end
local function pluralize(sOut, plural)
if plural then
sOut = sOut .. 's'
end
return sOut
end
local function normalizeType(s)
return mw.ustring.lower(mw.text.trim(tostring(s or '')))
end
local function argExists(args, key)
return args[key] ~= nil and tostring(args[key]) ~= ''
end
local function addRecipe(category, sAmt, sName)
local cardNode = Card._main({
name = sName,
text = sAmt,
show_caption = '1',
mobile = 'bulleted'
})
category:wikitext(
'[[Category:Uses ',
sName,
'|',
padLeft(tostring(sAmt or ''):gsub('%D', ''), 10),
']]'
)
return cardNode
end
local function addSimpleCard(sName, sText)
return Card._main({
name = sName,
text = sText,
show_caption = '1',
mobile = 'bulleted'
})
end
local function renderHeader(args, output, category)
local header = output:tag('div'):addClass('recipe_header')
local sType = args[param.sTypeArg]
header:tag('span'):addClass('recipe_header_main')
-- Mobile Icon/Text, preserved from original
:tag('span'):addClass('mobileHide'):wikitext('<big>' .. sType .. '</big>'):done()
-- Desktop Icon/Text, preserved from original
:tag('span'):addClass('mobileHide'):wikitext('<big>' .. sType .. '</big>'):done()
-- Text
:tag('span'):addClass('recipe_header_text'):wikitext('[[' .. sType .. ']]'):done()
category:wikitext('[[Category:' .. sType .. ']]')
return header
end
local function renderTime(args, header)
if type(args[param.sTimeArg]) ~= 'string' then
return
end
local tTime = {}
local key = false
local plural = false
for n1, d, n2, h, n3, m, n4, s in mw.ustring.gmatch(
args[param.sTimeArg],
'(%d+)(d?)(%d*)(h?)(%d*)(m?)(%d*)(s?)'
) do
table.insert(tTime, n1)
if n1 ~= '1' then
plural = true
end
if d == 'd' then
table.insert(tTime, pluralize('day', plural))
plural = false
key = true
end
if n2 ~= '' then
table.insert(tTime, n2)
if n2 ~= '1' then
plural = true
end
end
if h == 'h' then
table.insert(tTime, pluralize('hour', plural))
plural = false
key = true
end
if n3 ~= '' then
table.insert(tTime, n3)
if n3 ~= '1' then
plural = true
end
end
if m == 'm' then
table.insert(tTime, pluralize('minute', plural))
plural = false
key = true
end
if n4 ~= '' then
table.insert(tTime, n4)
if n4 ~= '1' then
plural = true
end
end
if s == 's' then
table.insert(tTime, pluralize('second', plural))
key = true
end
end
if not key then
table.insert(tTime, pluralize('minute', plural))
end
local sTime = ''
for _, each in ipairs(tTime) do
sTime = sTime .. each .. ' '
end
header:tag('span'):addClass('recipe_header_sub')
:tag('span'):addClass('mobileHide'):wikitext(' for '):done()
:tag('span'):addClass('hidden'):wikitext(' for '):done()
:tag('span'):addClass('recipe_header_text'):wikitext(sTime):done()
end
local function renderCharacter(args, header)
if type(args[param.sCharArg]) ~= 'string' then
return
end
local sCharName = args[param.sCharArg]
header:tag('span'):addClass('recipe_header_sub')
:tag('span'):addClass('mobileHide'):wikitext(' with '):done()
:tag('span'):addClass('hidden'):wikitext('[[File:' .. sCharName .. ' Icon.png|24x24px|link=' .. sCharName .. ']]'):done()
:tag('span'):addClass('recipe_header_text'):wikitext('[[' .. sCharName .. ']]'):done()
end
local function renderYield(args, body)
if args[param.sYieldArg] == '0' then
return
end
local sYield = args[param.sYieldArg] or '1'
local pageTitle = args.page or mw.title.getCurrentTitle().text
local yieldCard = Card._main({
name = pageTitle,
text = sYield,
show_caption = '1',
})
body
:tag('div'):addClass('recipe_body_icon')
:wikitext('➜'):done()
:tag('div'):addClass('recipe_body_yield')
:node(yieldCard)
-- Preserved from original, though unused.
local itemText = require('Module:Item').main{
[1] = pageTitle,
[2] = '15',
x = sYield
}
end
--------------------------------------------------------------------------------
-- Standard, non-cooking recipe rendering
--------------------------------------------------------------------------------
local function renderStandardRecipe(args, frame, output, category)
local tArgsProcessed = {}
local header = renderHeader(args, output, category)
renderTime(args, header)
renderCharacter(args, header)
local body = output:tag('div'):addClass('recipe_body')
local sSortDelim = param.sSortDelim
-- Check if sSortDelim2 exists in sSortArg.
if ((args[param.sSortArg] or ''):find(param.sSortDelim2) ~= nil) then
sSortDelim = param.sSortDelim2
end
-- Process Sort Parameter, split by delimiter.
for sKey in string.gmatch(args[param.sSortArg] or '', '([^' .. sSortDelim .. ']+)') do
if type(args[sKey]) ~= 'nil' then
body:node(addRecipe(category, args[sKey], sKey))
tArgsProcessed[sKey] = true
end
end
-- Process rest of unrestricted parameters.
for sKey, sVal in pairs(args) do
local restricted = false
for _, keyParam in pairs(param) do
if keyParam == sKey then
restricted = true
end
end
if tArgsProcessed[sKey] ~= true and not restricted then
body:node(addRecipe(category, sVal, sKey))
end
end
renderYield(args, body)
body:done()
end
--------------------------------------------------------------------------------
-- Cooking recipe rendering
--------------------------------------------------------------------------------
local function getCookingIngredient(args, index)
local prefix = 'item_' .. index
local ingredient = {
index = index,
amount = args[prefix .. '_amount'] or '1',
quality = args[prefix .. '_quality'],
item = args[prefix],
types = {},
options = {}
}
-- Single type:
-- |item_1_type = Fish
if argExists(args, prefix .. '_type') then
table.insert(ingredient.types, args[prefix .. '_type'])
end
-- Multiple types:
-- |item_1_type_1 = Freshwater Fish
-- |item_1_type_2 = Saltwater Fish
local typeIndex = 1
while argExists(args, prefix .. '_type_' .. typeIndex) do
table.insert(ingredient.types, args[prefix .. '_type_' .. typeIndex])
typeIndex = typeIndex + 1
end
-- Multiple accepted specific items:
-- |item_1_option_1 = Rice
-- |item_1_option_2 = Wheat
local optionIndex = 1
while argExists(args, prefix .. '_option_' .. optionIndex) do
table.insert(ingredient.options, args[prefix .. '_option_' .. optionIndex])
optionIndex = optionIndex + 1
end
local hasIngredient =
ingredient.item ~= nil
or #ingredient.types > 0
or #ingredient.options > 0
if not hasIngredient then
return nil
end
return ingredient
end
local function getKitchenware(args)
local kitchenware = {}
-- Single kitchenware:
-- |kitchenware = Cooking Pot
if argExists(args, 'kitchenware') then
table.insert(kitchenware, args.kitchenware)
end
-- Multiple kitchenware:
-- |kitchenware_1 = Cooking Pot
-- |kitchenware_2 = Frying Pan
local index = 1
while argExists(args, 'kitchenware_' .. index) do
table.insert(kitchenware, args['kitchenware_' .. index])
index = index + 1
end
return kitchenware
end
local function renderCookingTypeRequirement(category, typeBox, amountText, types)
if #types == 1 then
local typeName = types[1]
typeBox:tag('div')
:addClass('recipe_body_cooking_requirement')
:wikitext(amountText .. ' of [[:Category:' .. typeName .. '|' .. typeName .. ']]')
category:wikitext('[[Category:Uses ', typeName, ']]')
return
end
typeBox:tag('div')
:addClass('recipe_body_cooking_requirement')
:wikitext(amountText .. ' of any of:')
for _, typeName in ipairs(types) do
typeBox:tag('div')
:addClass('recipe_body_cooking_type')
:wikitext('[[:Category:' .. typeName .. '|' .. typeName .. ']]')
category:wikitext('[[Category:Uses ', typeName, ']]')
end
end
local function renderCookingIngredient(category, body, ingredient)
local wrapper = body:tag('div')
:addClass('recipe_body_cooking_ingredient')
local amountText = tostring(ingredient.amount or '1')
if ingredient.quality then
amountText = amountText .. ' ' .. ingredient.quality
end
-- Specific item:
-- |item_1 = Rice
if ingredient.item then
wrapper:node(addRecipe(category, amountText, ingredient.item))
return
end
-- Multiple specific item options:
-- |item_1_option_1 = Rice
-- |item_1_option_2 = Wheat
if #ingredient.options > 0 then
local optionBox = wrapper:tag('div')
:addClass('recipe_body_cooking_options')
optionBox:tag('div')
:addClass('recipe_body_cooking_requirement')
:wikitext(amountText .. ' of any of:')
for _, itemName in ipairs(ingredient.options) do
optionBox:node(addRecipe(category, '', itemName))
end
return
end
-- Type-based ingredient:
-- |item_1_type = Fish
-- or:
-- |item_1_type_1 = Freshwater Fish
-- |item_1_type_2 = Saltwater Fish
if #ingredient.types > 0 then
local typeBox = wrapper:tag('div')
:addClass('recipe_body_cooking_types')
renderCookingTypeRequirement(category, typeBox, amountText, ingredient.types)
return
end
end
local function renderKitchenware(category, body, args)
local kitchenware = getKitchenware(args)
if #kitchenware == 0 then
return
end
local wrapper = body:tag('div')
:addClass('recipe_body_kitchenware')
wrapper:tag('div')
:addClass('recipe_body_kitchenware_label')
:wikitext('Kitchenware')
for _, itemName in ipairs(kitchenware) do
wrapper:node(addSimpleCard(itemName, ''))
category:wikitext('[[Category:Uses ', itemName, ']]')
end
end
local function renderCookingRecipe(args, frame, output, category)
local header = renderHeader(args, output, category)
renderTime(args, header)
renderCharacter(args, header)
local body = output:tag('div')
:addClass('recipe_body')
:addClass('recipe_body_cooking')
local ingredientIndex = 1
local foundIngredient = false
while true do
local ingredient = getCookingIngredient(args, ingredientIndex)
if not ingredient then
break
end
foundIngredient = true
renderCookingIngredient(category, body, ingredient)
ingredientIndex = ingredientIndex + 1
end
if not foundIngredient then
body:tag('span')
:addClass('error')
:wikitext('Cooking recipe error. No cooking ingredients found.')
end
renderKitchenware(category, body, args)
renderYield(args, body)
body:done()
end
--------------------------------------------------------------------------------
-- Entry points
--------------------------------------------------------------------------------
function p.main(frame)
local args = require('Module:Arguments').getArgs(frame, {
parentFirst = true,
wrapper = { 'Template:Recipe' }
})
return p._main(args, frame)
end
function p._main(args, frame)
local output = mw.html.create('div')
:addClass('recipe_container')
-- Important: category must be local to this render.
-- Do not keep it as a module-level variable.
local category = mw.html.create()
if type(args[param.sTypeArg]) ~= 'string' then
output:tag('span')
:addClass('error')
:wikitext('Recipe type error. Must include recipe type.')
else
local sType = args[param.sTypeArg]
if normalizeType(sType) == 'cooking' then
renderCookingRecipe(args, frame, output, category)
else
renderStandardRecipe(args, frame, output, category)
end
end
output:node(require('Module:Namespace detect').main({
["main"] = category
}))
return output
end
return p