Editing Module:Recipe

Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.
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 6: Line 6:
local param = {
local param = {
   sCharArg = 'character',
   sCharArg = 'character',
  sKitchArg = 'kitchenware',
   sTypeArg = 'type',
   sTypeArg = 'type',
   sSortArg = 'sort',
   sSortArg = 'sort',
   sSortDelim = ';',
   sSortDelim = ';', -- Needs to be pattern-safe for current usage
   sSortDelim2 = '¤',
   sSortDelim2 = '¤',
   sTimeArg = 'time',
   sTimeArg = 'time',
Line 17: Line 16:


p.param = param
p.param = param
--------------------------------------------------------------------------------
-- Utility
--------------------------------------------------------------------------------


local function padLeft(str, amt)
local function padLeft(str, amt)
Line 31: Line 26:
     sOut = sOut .. 's'
     sOut = sOut .. 's'
   end
   end
   return sOut
   return sOut
end
end


local function normalizeText(s)
local function normalizeType(s)
   return mw.ustring.lower(mw.text.trim(tostring(s or '')))
   return mw.ustring.lower(mw.text.trim(tostring(s or '')))
end
end
Line 43: Line 37:
end
end


local function addUseCategory(category, name, quality, sort)
local function addRecipe(category, sAmt, sName)
if not name or tostring(name) == '' then
   local cardNode = Card._main({
return
end
 
if quality and tostring(quality) ~= '' then
if sort and tostring(sort) ~= '' then
category:wikitext('[[Category:Uses ', quality, '-Quality ', name, '|', sort, ']]')
else
category:wikitext('[[Category:Uses ', quality, '-Quality ', name, ']]')
end
 
return
end
 
if sort and tostring(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,
     name = sName,
     text = sAmt,
     text = sAmt,
     show_caption = '1'
     show_caption = '1',
  }
     mobile = 'bulleted'
 
   })
  if quality then
     cardArgs.quality = quality
   end


   local cardNode = Card._main(cardArgs)
   category:wikitext(
 
     '[[Category:Uses ',
  addUseCategory(
     category,
     sName,
     sName,
     quality,
     '|',
     padLeft(tostring(sAmt or ''):gsub('%D', ''), 10)
     padLeft(tostring(sAmt or ''):gsub('%D', ''), 10),
    ']]'
   )
   )


Line 104: Line 56:
end
end


local function addMiniCard(category, sName, sText, quality)
local function addSimpleCard(sName, sText)
   local cardArgs = {
   return Card._main({
     name = sName,
     name = sName,
     text = sText or '',
     text = sText,
     show_caption = '1',
     show_caption = '1',
     mini = '1'
     mobile = 'bulleted'
  }
 
  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
end


--------------------------------------------------------------------------------
local function renderHeader(args, output, category)
-- Header rendering
  local header = output:tag('div'):addClass('recipe_header')
--------------------------------------------------------------------------------


local function renderHeader(args, output, category)
  local header = output:tag('div'):addClass('recipe-header')
   local sType = args[param.sTypeArg]
   local sType = args[param.sTypeArg]


   header:tag('span'):addClass('recipe-header-main')
   header:tag('span'):addClass('recipe_header_main')
     :tag('span'):addClass('recipe-header-text'):wikitext('[[' .. sType .. ']]'):done()
    -- 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 .. ']]')
   category:wikitext('[[Category:' .. sType .. ']]')
Line 224: Line 160:
   end
   end


   header:tag('span'):addClass('recipe-header-sub')
   header:tag('span'):addClass('recipe_header_sub')
     :tag('span'):wikitext(' for '):done()
     :tag('span'):addClass('mobileHide'):wikitext(' for '):done()
     :tag('span'):addClass('recipe-header-text'):wikitext(sTime):done()
    :tag('span'):addClass('hidden'):wikitext(' for '):done()
     :tag('span'):addClass('recipe_header_text'):wikitext(sTime):done()
end
end


Line 236: Line 173:
   local sCharName = args[param.sCharArg]
   local sCharName = args[param.sCharArg]


   header:tag('span'):addClass('recipe-header-sub')
   header:tag('span'):addClass('recipe_header_sub')
    :tag('span'):wikitext('[[File:' .. sCharName .. ' Icon.png|24x24px|link=' .. sCharName .. ']]'):done()
     :tag('span'):addClass('mobileHide'):wikitext(' with '):done()
     :tag('span'):addClass('recipe-header-text'):wikitext('[[' .. sCharName .. ']]'):done()
     :tag('span'):addClass('hidden'):wikitext('[[File:' .. sCharName .. ' Icon.png|24x24px|link=' .. sCharName .. ']]'):done()
end
     :tag('span'):addClass('recipe_header_text'):wikitext('[[' .. sCharName .. ']]'):done()
 
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'):wikitext('[[File:' .. sKitchName .. ' Icon.png|24x24px|link=' .. sKitchName .. ']]'):done()
     :tag('span'):addClass('recipe-header-text'):wikitext('[[' .. sKitchName .. ']]'):done()
end
end


--------------------------------------------------------------------------------
local function renderYield(args, body)
-- 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
   if args[param.sYieldArg] == '0' then
     return
     return
   end
   end


   local sYield = args[param.sYieldArg] or nil
   local sYield = args[param.sYieldArg] or '1'
   local pageTitle = getCurrentPageName(args)
   local pageTitle = args.page or mw.title.getCurrentTitle().text


   local yieldCard = addYieldCard(pageTitle, sYield)
   local yieldCard = Card._main({
    name = pageTitle,
    text = sYield,
    show_caption = '1',
  })


   body
   body
     :tag('div'):addClass('recipe-body-icon')
     :tag('div'):addClass('recipe_body_icon')
       :wikitext('➜'):done()
       :wikitext('➜'):done()
     :tag('div'):addClass('recipe-body-yield')
     :tag('div'):addClass('recipe_body_yield')
       :node(yieldCard)
       :node(yieldCard)
  -- Preserved from original, though unused.
  local itemText = require('Module:Item').main{
    [1] = pageTitle,
    [2] = '15',
    x = sYield
  }
end
end
--------------------------------------------------------------------------------
-- Standard, non-cooking recipe rendering
--------------------------------------------------------------------------------


local function renderStandardRecipe(args, frame, output, category)
local function renderStandardRecipe(args, frame, output, category)
Line 292: Line 219:
   renderCharacter(args, header)
   renderCharacter(args, header)


   local body = output:tag('div'):addClass('recipe-body')
   local body = output:tag('div'):addClass('recipe_body')


   local sSortDelim = param.sSortDelim
   local sSortDelim = param.sSortDelim


  -- Check if sSortDelim2 exists in sSortArg.
   if ((args[param.sSortArg] or ''):find(param.sSortDelim2) ~= nil) then
   if ((args[param.sSortArg] or ''):find(param.sSortDelim2) ~= nil) then
     sSortDelim = param.sSortDelim2
     sSortDelim = param.sSortDelim2
   end
   end


  -- Process Sort Parameter, split by delimiter.
   for sKey in string.gmatch(args[param.sSortArg] or '', '([^' .. sSortDelim .. ']+)') do
   for sKey in string.gmatch(args[param.sSortArg] or '', '([^' .. sSortDelim .. ']+)') do
     if type(args[sKey]) ~= 'nil' then
     if type(args[sKey]) ~= 'nil' then
       body:node(addRecipeCard(category, args[sKey], sKey))
       body:node(addRecipe(category, args[sKey], sKey))
       tArgsProcessed[sKey] = true
       tArgsProcessed[sKey] = true
     end
     end
   end
   end


  -- Process rest of unrestricted parameters.
   for sKey, sVal in pairs(args) do
   for sKey, sVal in pairs(args) do
     if tArgsProcessed[sKey] ~= true and not isRestrictedStandardParam(sKey) then
    local restricted = false
       body:node(addRecipeCard(category, sVal, sKey))
 
    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
   end
   end


   renderStandardYield(args, body)
   renderYield(args, body)


   body:done()
   body:done()
Line 319: Line 257:


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Cooking parsing
-- Cooking recipe rendering
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
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 function getCookingIngredient(args, index)
Line 344: Line 265:
   local ingredient = {
   local ingredient = {
     index = index,
     index = index,
     amount = args[prefix .. '_amount'] or nil,
     amount = args[prefix .. '_amount'] or '1',
     quality = args[prefix .. '_quality'],
     quality = args[prefix .. '_quality'],
     item = args[prefix],
     item = args[prefix],
Line 351: Line 272:
   }
   }


  -- Single type:
  -- |item_1_type = Fish
   if argExists(args, prefix .. '_type') then
   if argExists(args, prefix .. '_type') then
     table.insert(ingredient.types, args[prefix .. '_type'])
     table.insert(ingredient.types, args[prefix .. '_type'])
   end
   end


  -- Multiple types:
  -- |item_1_type_1 = Freshwater Fish
  -- |item_1_type_2 = Saltwater Fish
   local typeIndex = 1
   local typeIndex = 1


Line 362: Line 288:
   end
   end


  -- Multiple accepted specific items:
  -- |item_1_option_1 = Rice
  -- |item_1_option_2 = Wheat
   local optionIndex = 1
   local optionIndex = 1


Line 370: Line 299:


   local hasIngredient =
   local hasIngredient =
     argExists(args, prefix)
     ingredient.item ~= nil
     or #ingredient.types > 0
     or #ingredient.types > 0
     or #ingredient.options > 0
     or #ingredient.options > 0
Line 381: Line 310:
end
end


--------------------------------------------------------------------------------
local function getKitchenware(args)
-- Cooking type split-card helpers
  local kitchenware = {}
--------------------------------------------------------------------------------


local function makeTypeIcon(typeName)
  -- Single kitchenware:
   return '[[File:' .. typeName .. ' Icon.png|74x74px|link=' .. typeName .. ']]'
   -- |kitchenware = Cooking Pot
end
  if argExists(args, 'kitchenware') then
    table.insert(kitchenware, args.kitchenware)
  end


local function joinTypeCaption(types)
  -- Multiple kitchenware:
   local out = {}
  -- |kitchenware_1 = Cooking Pot
  -- |kitchenware_2 = Frying Pan
   local index = 1


   for _, typeName in ipairs(types) do
   while argExists(args, 'kitchenware_' .. index) do
     table.insert(out, '[[' .. typeName .. ']]')
     table.insert(kitchenware, args['kitchenware_' .. index])
    index = index + 1
   end
   end


   return table.concat(out, ' / ')
   return kitchenware
end
end


local function renderCookingSplitTypeCard(category, body, ingredient)
local function renderCookingTypeRequirement(category, typeBox, amountText, types)
   local qualityClass = getQualityClass(ingredient.quality or 'Gray')
   if #types == 1 then
    local typeName = types[1]


  local container = body:tag('span')
    typeBox:tag('div')
    :addClass('card-container')
      :addClass('recipe_body_cooking_requirement')
    :addClass('recipe-type-split-card')
      :wikitext(amountText .. ' of [[:Category:' .. typeName .. '|' .. typeName .. ']]')


  local wrapper = container:tag('span')
    category:wikitext('[[Category:Uses ', typeName, ']]')
    :addClass('card-wrapper')


   local cardBody = wrapper:tag('span')
    return
    :addClass('card-body')
   end


   local imageContainer = cardBody:tag('span')
   typeBox:tag('div')
     :addClass('card-image-container')
     :addClass('recipe_body_cooking_requirement')
     :addClass('recipe-type-split-image')
     :wikitext(amountText .. ' of any of:')


   imageContainer:tag('span')
   for _, typeName in ipairs(types) do
     :addClass('recipe-type-split-half')
     typeBox:tag('div')
    :addClass('recipe-type-split-half-a')
      :addClass('recipe_body_cooking_type')
    :wikitext(makeTypeIcon(ingredient.types[1]))
      :wikitext('[[:Category:' .. typeName .. '|' .. typeName .. ']]')
    :done()
 
  imageContainer:tag('span')
    :addClass('recipe-type-split-half')
    :addClass('recipe-type-split-half-b')
    :wikitext(makeTypeIcon(ingredient.types[2]))
    :done()
   
if qualityClass then
    imageContainer:addClass(qualityClass)
end


  if tostring(ingredient.amount or '') ~= '' then
     category:wikitext('[[Category:Uses ', typeName, ']]')
     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
end
end


--------------------------------------------------------------------------------
local function renderCookingIngredient(category, body, ingredient)
-- 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')
   local wrapper = body:tag('div')
     :addClass('recipe-body-cooking-ingredient')
     :addClass('recipe_body_cooking_ingredient')
    :addClass('recipe-body-cooking-type-cards')


   for _, typeName in ipairs(ingredient.types) do
   local amountText = tostring(ingredient.amount or '1')
    wrapper:node(addMiniCard(
      category,
      typeName,
      ingredient.amount,
      ingredient.quality
    ))
  end
end


local function renderCookingTypeCards(category, body, ingredient)
   if ingredient.quality then
   if #ingredient.types == 2 then
     amountText = amountText .. ' ' .. ingredient.quality
     renderCookingSplitTypeCard(category, body, ingredient)
  else
    renderCookingTypeFallback(category, body, ingredient)
   end
   end
end


local function renderCookingOptionCards(category, body, ingredient)
   -- Specific item:
   local wrapper = body:tag('div')
  -- |item_1 = Rice
    :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
   if ingredient.item then
     renderCookingSpecificItem(category, body, ingredient)
     wrapper:node(addRecipe(category, amountText, ingredient.item))
     return
     return
   end
   end


  -- Multiple specific item options:
  -- |item_1_option_1 = Rice
  -- |item_1_option_2 = Wheat
   if #ingredient.options > 0 then
   if #ingredient.options > 0 then
     renderCookingOptionCards(category, body, ingredient)
     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
     return
   end
   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
   if #ingredient.types > 0 then
     renderCookingTypeCards(category, body, ingredient)
     local typeBox = wrapper:tag('div')
      :addClass('recipe_body_cooking_types')
 
    renderCookingTypeRequirement(category, typeBox, amountText, ingredient.types)
 
     return
     return
   end
   end
end
end


local function renderCookingYield(args, category, body)
local function renderKitchenware(category, body, args)
   if args[param.sYieldArg] == '0' then
  local kitchenware = getKitchenware(args)
 
   if #kitchenware == 0 then
     return
     return
   end
   end


   local sYield = args[param.sYieldArg] or nil
   local wrapper = body:tag('div')
  local pageTitle = getCurrentPageName(args)
    :addClass('recipe_body_kitchenware')


   local yieldCard = addYieldCard(pageTitle, sYield)
   wrapper:tag('div')
    :addClass('recipe_body_kitchenware_label')
    :wikitext('Kitchenware')


   body
   for _, itemName in ipairs(kitchenware) do
     :tag('div'):addClass('recipe-body-icon')
     wrapper:node(addSimpleCard(itemName, ''))
      :wikitext('➜'):done()
    category:wikitext('[[Category:Uses ', itemName, ']]')
    :tag('div'):addClass('recipe-body-yield')
  end
      :node(yieldCard)
end
end


Line 539: Line 433:
   renderTime(args, header)
   renderTime(args, header)
   renderCharacter(args, header)
   renderCharacter(args, header)
  renderKitchenwareHeader(args, header)


   local body = output:tag('div')
   local body = output:tag('div')
     :addClass('recipe-body')
     :addClass('recipe_body')
     :addClass('recipe-body-cooking')
     :addClass('recipe_body_cooking')


  local ingredientIndex = 1
   local foundIngredient = false
   local foundIngredient = false
  local maxIndex = getMaxCookingItemIndex(args)


   for index = 1, maxIndex do
   while true do
     local ingredient = getCookingIngredient(args, index)
     local ingredient = getCookingIngredient(args, ingredientIndex)


     if ingredient then
     if not ingredient then
       foundIngredient = true
       break
      renderCookingIngredient(category, body, ingredient)
     end
     end
    foundIngredient = true
    renderCookingIngredient(category, body, ingredient)
    ingredientIndex = ingredientIndex + 1
   end
   end


Line 563: Line 460:
   end
   end


   renderCookingYield(args, category, body)
   renderKitchenware(category, body, args)
 
  renderYield(args, body)


   body:done()
   body:done()
Line 583: Line 482:
function p._main(args, frame)
function p._main(args, frame)
   local output = mw.html.create('div')
   local output = mw.html.create('div')
     :addClass('recipe-container')
     :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()
   local category = mw.html.create()


Line 594: Line 495:
     local sType = args[param.sTypeArg]
     local sType = args[param.sTypeArg]


     if normalizeText(sType) == 'cooking' then
     if normalizeType(sType) == 'cooking' then
       renderCookingRecipe(args, frame, output, category)
       renderCookingRecipe(args, frame, output, category)
     else
     else
Please note that all contributions to The Petit Planet Wiki are considered to be released under the Creative Commons Attribution-ShareAlike (see Petit Planet Wiki:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!
Cancel Editing help (opens in new window)
Preview page with this template
Below are commonly used wikitext from MediaWiki:Edittools. Click on any to insert them in the edit box.
File Pages==Summary====Licensing=={{Fairuse}}{{File|}}
Dynamic Page List¦²«»²{¦}²«»«/»«!----»
Array in DPL¹^2{}^2^2{¹}^2
Parser Functions{{#if:||}}
{{#ifeq:|||}}
{{#expr:}}
{{#switch:||#default=}}
{{#replace:||}}
{{#titleparts:}}
{{#tag:|}}
Markup{{}}|[][[]][[Category:]]#REDIRECT [[]] [[Category:Redirect Pages]]<code></code><includeonly></includeonly><noinclude></noinclude><nowiki></nowiki><!----><br>§
Notices{{Stub|}}{{Stub Dialogue}}{{Upcoming}}{{Under Construction}}{{Placeholder|}}
Magic Words{{!}}{{formatnum:}}{{lc:}}{{uc:}}{{PAGENAME}}{{FULLPAGENAME}}{{ROOTPAGENAME}}{{BASEPAGENAME}}{{SUBPAGENAME}}{{DISPLAYTITLE:|noreplace}}__TOC____NOTOC____EXPECTUNUSEDCATEGORY____HIDDENCAT__
HTML Entities&mdash;&nbsp;&comma;&shy;