Editing Module:Sandbox/Stevium
From The Petit Planet Wiki
More actions
The edit can be undone.
Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
| Latest revision | Your text | ||
| Line 1: | Line 1: | ||
local p = {} | local p = {} | ||
function | local Card = require('Module:Card') | ||
-- Arguments for template | |||
local param = { | |||
sCharArg = 'character', | |||
sKitchArg = 'kitchenware', | |||
sTypeArg = 'type', | |||
sSortArg = 'sort', | |||
sSortDelim = ';', | |||
sSortDelim2 = '¤', | |||
sTimeArg = 'time', | |||
sYieldArg = 'yield', | |||
sPage = 'page' | |||
} | |||
p.param = param | |||
-------------------------------------------------------------------------------- | |||
-- Utility | |||
-------------------------------------------------------------------------------- | |||
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 normalizeText(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 addUseCategory(category, name, sort) | |||
if not name or tostring(name) == '' then | |||
return | |||
end | |||
if sort then | |||
category:wikitext('[[Category:Uses ', name, '|', sort, ']]') | |||
else | |||
category:wikitext('[[Category:Uses ', name, ']]') | |||
end | |||
end | |||
local function getCurrentPageName(args) | |||
return args[param.sPage] or args.page or mw.title.getCurrentTitle().text | |||
end | |||
local function getQualityClass(quality) | |||
if not quality or tostring(quality) == '' then | |||
return nil | |||
end | |||
return 'card-quality-' .. normalizeText(quality) | |||
end | |||
-------------------------------------------------------------------------------- | |||
-- Card helpers | |||
-------------------------------------------------------------------------------- | |||
local function addRecipeCard(category, sAmt, sName, quality) | |||
local cardArgs = { | |||
name = sName, | |||
text = sAmt, | |||
show_caption = '1', | |||
mobile = 'bulleted' | |||
} | |||
if quality then | |||
cardArgs.quality = quality | |||
end | |||
local cardNode = Card._main(cardArgs) | |||
addUseCategory( | |||
category, | |||
sName, | |||
padLeft(tostring(sAmt or ''):gsub('%D', ''), 10) | |||
) | |||
return cardNode | |||
end | |||
local function addMiniCard(category, sName, sText, quality) | |||
local cardArgs = { | |||
name = sName, | |||
text = sText or '', | |||
show_caption = '1', | |||
mobile = 'bulleted', | |||
mini = '1' | |||
} | |||
if quality then | |||
cardArgs.quality = quality | |||
end | |||
local cardNode = Card._main(cardArgs) | |||
addUseCategory(category, sName) | |||
return cardNode | |||
end | |||
local function addYieldCard(pageTitle, sYield) | |||
return Card._main({ | |||
name = pageTitle, | |||
text = sYield, | |||
show_caption = '1' | |||
}) | |||
end | |||
-------------------------------------------------------------------------------- | |||
-- Header rendering | |||
-------------------------------------------------------------------------------- | |||
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') | |||
:tag('span'):addClass('mobileHide'):wikitext('<big>' .. sType .. '</big>'):done() | |||
:tag('span'):addClass('mobileHide'):wikitext('<big>' .. sType .. '</big>'):done() | |||
: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 renderKitchenwareHeader(args, header) | |||
if type(args[param.sKitchArg]) ~= 'string' then | |||
return | |||
end | |||
local sKitchName = args[param.sKitchArg] | |||
header:tag('span'):addClass('recipe_header_sub') | |||
:tag('span'):addClass('mobileHide'):wikitext(' with '):done() | |||
:tag('span'):addClass('hidden'):wikitext('[[File:' .. sKitchName .. ' Icon.png|24x24px|link=' .. sKitchName .. ']]'):done() | |||
:tag('span'):addClass('recipe_header_text'):wikitext('[[' .. sKitchName .. ']]'):done() | |||
end | |||
-------------------------------------------------------------------------------- | |||
-- Standard recipe rendering | |||
-------------------------------------------------------------------------------- | |||
local function isRestrictedStandardParam(sKey) | |||
for _, keyParam in pairs(param) do | |||
if keyParam == sKey then | |||
return true | |||
end | |||
end | |||
return false | |||
end | |||
local function renderStandardYield(args, body) | |||
if args[param.sYieldArg] == '0' then | |||
return | |||
end | |||
local sYield = args[param.sYieldArg] or '1' | |||
local pageTitle = getCurrentPageName(args) | |||
local yieldCard = addYieldCard(pageTitle, sYield) | |||
body | |||
:tag('div'):addClass('recipe_body_icon') | |||
:wikitext('➜'):done() | |||
:tag('div'):addClass('recipe_body_yield') | |||
:node(yieldCard) | |||
end | |||
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 | |||
if ((args[param.sSortArg] or ''):find(param.sSortDelim2) ~= nil) then | |||
sSortDelim = param.sSortDelim2 | |||
end | |||
for sKey in string.gmatch(args[param.sSortArg] or '', '([^' .. sSortDelim .. ']+)') do | |||
if type(args[sKey]) ~= 'nil' then | |||
body:node(addRecipeCard(category, args[sKey], sKey)) | |||
tArgsProcessed[sKey] = true | |||
end | |||
end | |||
for sKey, sVal in pairs(args) do | |||
if tArgsProcessed[sKey] ~= true and not isRestrictedStandardParam(sKey) then | |||
body:node(addRecipeCard(category, sVal, sKey)) | |||
end | |||
end | |||
renderStandardYield(args, body) | |||
body:done() | |||
end | |||
-------------------------------------------------------------------------------- | |||
-- Cooking parsing | |||
-------------------------------------------------------------------------------- | |||
local function getMaxCookingItemIndex(args) | |||
local maxIndex = 0 | |||
for key, _ in pairs(args) do | |||
local index = tostring(key):match('^item_(%d+)') | |||
if index then | |||
index = tonumber(index) | |||
if index and index > maxIndex then | |||
maxIndex = index | |||
end | |||
end | |||
end | |||
return maxIndex | |||
end | |||
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 = {} | |||
} | |||
if argExists(args, prefix .. '_type') then | |||
table.insert(ingredient.types, args[prefix .. '_type']) | |||
end | |||
local typeIndex = 1 | |||
while argExists(args, prefix .. '_type_' .. typeIndex) do | |||
table.insert(ingredient.types, args[prefix .. '_type_' .. typeIndex]) | |||
typeIndex = typeIndex + 1 | |||
end | |||
local optionIndex = 1 | |||
while argExists(args, prefix .. '_option_' .. optionIndex) do | |||
table.insert(ingredient.options, args[prefix .. '_option_' .. optionIndex]) | |||
optionIndex = optionIndex + 1 | |||
end | |||
local hasIngredient = | |||
argExists(args, prefix) | |||
or #ingredient.types > 0 | |||
or #ingredient.options > 0 | |||
if not hasIngredient then | |||
return nil | |||
end | |||
return ingredient | |||
end | |||
-------------------------------------------------------------------------------- | |||
-- Cooking type split-card helpers | |||
-------------------------------------------------------------------------------- | |||
local function makeTypeIcon(typeName) | |||
return '[[File:' .. typeName .. ' Icon.png|74x74px|link=' .. typeName .. ']]' | |||
end | |||
local function joinTypeCaption(types) | |||
local out = {} | |||
for _, typeName in ipairs(types) do | |||
table.insert(out, '[[' .. typeName .. ']]') | |||
end | |||
return table.concat(out, ' / ') | |||
end | |||
local function renderCookingSplitTypeCard(category, body, ingredient) | |||
local qualityClass = getQualityClass(ingredient.quality) | |||
local container = body:tag('span') | |||
:addClass('card-container') | |||
:addClass('recipe-type-split-card') | |||
if qualityClass then | |||
container:addClass(qualityClass) | |||
end | |||
local wrapper = container:tag('span') | |||
:addClass('card-wrapper') | |||
local cardBody = wrapper:tag('span') | |||
:addClass('card-body') | |||
local imageContainer = cardBody:tag('span') | |||
:addClass('card-image-container') | |||
:addClass('recipe-type-split-image') | |||
imageContainer:tag('span') | |||
:addClass('recipe-type-split-half') | |||
:addClass('recipe-type-split-half-a') | |||
:wikitext(makeTypeIcon(ingredient.types[1])) | |||
:done() | |||
imageContainer:tag('span') | |||
:addClass('recipe-type-split-half') | |||
:addClass('recipe-type-split-half-b') | |||
:wikitext(makeTypeIcon(ingredient.types[2])) | |||
:done() | |||
if tostring(ingredient.amount or '') ~= '' then | |||
container:tag('span') | |||
:addClass('card-label') | |||
:wikitext(tostring(ingredient.amount or '1')) | |||
:done() | |||
end | |||
container:tag('span') | |||
:addClass('card-caption') | |||
:wikitext(joinTypeCaption(ingredient.types)) | |||
:done() | |||
for _, typeName in ipairs(ingredient.types) do | |||
addUseCategory(category, typeName) | |||
end | |||
end | |||
-------------------------------------------------------------------------------- | |||
-- Cooking display | |||
-------------------------------------------------------------------------------- | |||
local function renderCookingSpecificItem(category, body, ingredient) | |||
body:node(addRecipeCard( | |||
category, | |||
ingredient.amount, | |||
ingredient.item, | |||
ingredient.quality | |||
)) | |||
end | |||
local function renderCookingTypeFallback(category, body, ingredient) | |||
local wrapper = body:tag('div') | |||
:addClass('recipe_body_cooking_ingredient') | |||
:addClass('recipe_body_cooking_type_cards') | |||
for _, typeName in ipairs(ingredient.types) do | |||
wrapper:node(addMiniCard( | |||
category, | |||
typeName, | |||
ingredient.amount, | |||
ingredient.quality | |||
)) | |||
end | |||
end | |||
local function renderCookingTypeCards(category, body, ingredient) | |||
if #ingredient.types == 2 then | |||
renderCookingSplitTypeCard(category, body, ingredient) | |||
else | |||
renderCookingTypeFallback(category, body, ingredient) | |||
end | |||
end | |||
local function renderCookingOptionCards(category, body, ingredient) | |||
local wrapper = body:tag('div') | |||
:addClass('recipe_body_cooking_ingredient') | |||
:addClass('recipe_body_cooking_option_cards') | |||
for _, itemName in ipairs(ingredient.options) do | |||
wrapper:node(addMiniCard( | |||
category, | |||
itemName, | |||
ingredient.amount, | |||
ingredient.quality | |||
)) | |||
end | |||
end | |||
local function renderCookingIngredient(category, body, ingredient) | |||
if ingredient.item then | |||
renderCookingSpecificItem(category, body, ingredient) | |||
return | |||
end | |||
if #ingredient.options > 0 then | |||
renderCookingOptionCards(category, body, ingredient) | |||
return | |||
end | |||
if #ingredient.types > 0 then | |||
renderCookingTypeCards(category, body, ingredient) | |||
return | |||
end | |||
end | |||
local function renderCookingYield(args, category, body) | |||
if args[param.sYieldArg] == '0' then | |||
return | |||
end | |||
local sYield = args[param.sYieldArg] or '1' | |||
local pageTitle = getCurrentPageName(args) | |||
local yieldCard = addYieldCard(pageTitle, sYield) | |||
body | |||
:tag('div'):addClass('recipe_body_icon') | |||
:wikitext('➜'):done() | |||
:tag('div'):addClass('recipe_body_yield') | |||
:node(yieldCard) | |||
end | |||
local function renderCookingRecipe(args, frame, output, category) | |||
local header = renderHeader(args, output, category) | |||
renderTime(args, header) | |||
renderCharacter(args, header) | |||
renderKitchenwareHeader(args, header) | |||
local body = output:tag('div') | |||
:addClass('recipe_body') | |||
:addClass('recipe_body_cooking') | |||
local foundIngredient = false | |||
local maxIndex = getMaxCookingItemIndex(args) | |||
for index = 1, maxIndex do | |||
local ingredient = getCookingIngredient(args, index) | |||
if ingredient then | |||
foundIngredient = true | |||
renderCookingIngredient(category, body, ingredient) | |||
end | |||
end | |||
if not foundIngredient then | |||
body:tag('span') | |||
:addClass('error') | |||
:wikitext('Cooking recipe error. No cooking ingredients found.') | |||
end | |||
renderCookingYield(args, category, 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') | |||
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 normalizeText(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 | end | ||
return p | return p | ||