Module:Recipe: Difference between revisions

No edit summary
No edit summary
Line 8: Line 8:
   sTypeArg = 'type',
   sTypeArg = 'type',
   sSortArg = 'sort',
   sSortArg = 'sort',
   sSortDelim = ';', -- Needs to be pattern-safe for current usage
   sSortDelim = ';',
   sSortDelim2 = '¤',
   sSortDelim2 = '¤',
   sTimeArg = 'time',
   sTimeArg = 'time',
Line 16: Line 16:


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


local function padLeft(str, amt)
local function padLeft(str, amt)
Line 37: Line 41:
end
end


local function addRecipe(category, sAmt, sName)
local function joinDisplay(list, separator)
   local cardNode = Card._main({
  local out = {}
 
  for _, value in ipairs(list) do
    table.insert(out, '[[' .. value .. ']]')
  end
 
  return table.concat(out, separator or ' / ')
end
 
local function joinFileNameParts(list)
  return table.concat(list, ' & ')
end
 
--------------------------------------------------------------------------------
-- Card helpers
--------------------------------------------------------------------------------
 
local function addRecipe(category, sAmt, sName, quality)
   local cardArgs = {
     name = sName,
     name = sName,
     text = sAmt,
     text = sAmt,
     show_caption = '1',
     show_caption = '1',
     mobile = 'bulleted'
     mobile = 'bulleted'
   })
   }
 
  if quality then
    cardArgs.quality = quality
  end
 
  local cardNode = Card._main(cardArgs)


   category:wikitext(
   category:wikitext(
Line 56: Line 84:
end
end


local function addSimpleCard(sName, sText)
local function addMiniCard(category, sName, sText, quality)
   return Card._main({
   local cardArgs = {
     name = sName,
     name = sName,
     text = sText,
     text = sText or '',
     show_caption = '1',
     show_caption = '1',
     mobile = 'bulleted'
     mobile = 'bulleted',
   })
    mini = '1'
   }
 
  if quality then
    cardArgs.quality = quality
  end
 
  local cardNode = Card._main(cardArgs)
 
  if category and sName then
    category:wikitext('[[Category:Uses ', sName, ']]')
  end
 
  return cardNode
end
end
--------------------------------------------------------------------------------
-- Header rendering
--------------------------------------------------------------------------------


local function renderHeader(args, output, category)
local function renderHeader(args, output, category)
Line 71: Line 116:


   header:tag('span'):addClass('recipe_header_main')
   header:tag('span'):addClass('recipe_header_main')
    -- Mobile Icon/Text, preserved from original
     :tag('span'):addClass('mobileHide'):wikitext('<big>' .. sType .. '</big>'):done()
     :tag('span'):addClass('mobileHide'):wikitext('<big>' .. sType .. '</big>'):done()
    -- Desktop Icon/Text, preserved from original
     :tag('span'):addClass('mobileHide'):wikitext('<big>' .. sType .. '</big>'):done()
     :tag('span'):addClass('mobileHide'):wikitext('<big>' .. sType .. '</big>'):done()
    -- Text
     :tag('span'):addClass('recipe_header_text'):wikitext('[[' .. sType .. ']]'):done()
     :tag('span'):addClass('recipe_header_text'):wikitext('[[' .. sType .. ']]'):done()


Line 179: Line 221:
end
end


local function renderYield(args, body)
--------------------------------------------------------------------------------
-- Standard recipe rendering
--------------------------------------------------------------------------------
 
local function renderStandardYield(args, body)
   if args[param.sYieldArg] == '0' then
   if args[param.sYieldArg] == '0' then
     return
     return
Line 199: Line 245:
       :node(yieldCard)
       :node(yieldCard)


  -- Preserved from original, though unused.
   local itemText = require('Module:Item').main{
   local itemText = require('Module:Item').main{
     [1] = pageTitle,
     [1] = pageTitle,
Line 206: Line 251:
   }
   }
end
end
--------------------------------------------------------------------------------
-- Standard, non-cooking recipe rendering
--------------------------------------------------------------------------------


local function renderStandardRecipe(args, frame, output, category)
local function renderStandardRecipe(args, frame, output, category)
Line 223: Line 264:
   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
Line 236: Line 275:
   end
   end


  -- Process rest of unrestricted parameters.
   for sKey, sVal in pairs(args) do
   for sKey, sVal in pairs(args) do
     local restricted = false
     local restricted = false
Line 251: Line 289:
   end
   end


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


   body:done()
   body:done()
Line 257: Line 295:


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Cooking recipe rendering
-- Cooking recipe parsing
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


Line 272: Line 310:
   }
   }


  -- Single type:
   -- |item_1_type = Fish
   -- |item_1_type = Fish
   if argExists(args, prefix .. '_type') then
   if argExists(args, prefix .. '_type') then
Line 278: Line 315:
   end
   end


  -- Multiple types:
   -- |item_1_type_1 = Freshwater Fish
   -- |item_1_type_1 = Freshwater Fish
   -- |item_1_type_2 = Saltwater Fish
   -- |item_1_type_2 = Saltwater Fish
Line 288: Line 324:
   end
   end


  -- Multiple accepted specific items:
   -- |item_1_option_1 = Rice
   -- |item_1_option_1 = Rice
   -- |item_1_option_2 = Wheat
   -- |item_1_option_2 = Wheat
Line 313: Line 348:
   local kitchenware = {}
   local kitchenware = {}


  -- Single kitchenware:
  -- |kitchenware = Cooking Pot
   if argExists(args, 'kitchenware') then
   if argExists(args, 'kitchenware') then
     table.insert(kitchenware, args.kitchenware)
     table.insert(kitchenware, args.kitchenware)
   end
   end


  -- Multiple kitchenware:
  -- |kitchenware_1 = Cooking Pot
  -- |kitchenware_2 = Frying Pan
   local index = 1
   local index = 1


Line 332: Line 362:
end
end


local function renderCookingTypeRequirement(category, typeBox, amountText, types)
--------------------------------------------------------------------------------
  if #types == 1 then
-- Cooking recipe display
    local typeName = types[1]
--------------------------------------------------------------------------------


    typeBox:tag('div')
local function renderCookingTypeCard(category, body, ingredient)
      :addClass('recipe_body_cooking_requirement')
  local wrapper = body:tag('div')
      :wikitext(amountText .. ' of [[:Category:' .. typeName .. '|' .. typeName .. ']]')
    :addClass('recipe_body_cooking_ingredient')
    :addClass('recipe_body_cooking_type_card')


  local fileBase = joinFileNameParts(ingredient.types)
  local fileName = 'Recipe ' .. fileBase .. ' Icon.png'
  local caption = joinDisplay(ingredient.types, ' / ')
  for _, typeName in ipairs(ingredient.types) do
     category:wikitext('[[Category:Uses ', typeName, ']]')
     category:wikitext('[[Category:Uses ', typeName, ']]')
  end
  local amountText = tostring(ingredient.amount or '1')


     return
  local card = wrapper:tag('div')
     :addClass('card')
    :addClass('recipe-type-card')
 
  if ingredient.quality then
    card:addClass('card-quality-' .. normalizeType(ingredient.quality))
   end
   end


   typeBox:tag('div')
   card:tag('div')
     :addClass('recipe_body_cooking_requirement')
     :addClass('card-image')
     :wikitext(amountText .. ' of any of:')
     :wikitext('[[File:' .. fileName .. '|64x64px|link=]]')


   for _, typeName in ipairs(types) do
   card:tag('div')
    typeBox:tag('div')
    :addClass('card-caption')
      :addClass('recipe_body_cooking_type')
    :wikitext(caption)
      :wikitext('[[:Category:' .. typeName .. '|' .. typeName .. ']]')


     category:wikitext('[[Category:Uses ', typeName, ']]')
  if amountText ~= '' then
     card:tag('div')
      :addClass('card-text')
      :wikitext(amountText)
   end
   end
end
end


local function renderCookingIngredient(category, body, ingredient)
local function renderCookingOptionCards(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_options')


   local amountText = tostring(ingredient.amount or '1')
   for _, itemName in ipairs(ingredient.options) do
 
    wrapper:node(addRecipe(category, ingredient.amount, itemName, ingredient.quality))
  if ingredient.quality then
    amountText = amountText .. ' ' .. ingredient.quality
   end
   end
end


local function renderCookingIngredient(category, body, ingredient)
   -- Specific item:
   -- Specific item:
   -- |item_1 = Rice
   -- |item_1 = Rice
   if ingredient.item then
   if ingredient.item then
     wrapper:node(addRecipe(category, amountText, ingredient.item))
     body:node(addRecipe(category, ingredient.amount, ingredient.item, ingredient.quality))
     return
     return
   end
   end


   -- Multiple specific item options:
   -- Multiple accepted specific items:
   -- |item_1_option_1 = Rice
   -- |item_1_option_1 = Rice
   -- |item_1_option_2 = Wheat
   -- |item_1_option_2 = Wheat
   if #ingredient.options > 0 then
   if #ingredient.options > 0 then
     local optionBox = wrapper:tag('div')
     renderCookingOptionCards(category, body, ingredient)
      :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
Line 395: Line 432:
   -- Type-based ingredient:
   -- Type-based ingredient:
   -- |item_1_type = Fish
   -- |item_1_type = Fish
  -- or:
   -- |item_1_type_1 = Freshwater Fish
   -- |item_1_type_1 = Freshwater Fish
   -- |item_1_type_2 = Saltwater Fish
   -- |item_1_type_2 = Saltwater Fish
   if #ingredient.types > 0 then
   if #ingredient.types > 0 then
     local typeBox = wrapper:tag('div')
     renderCookingTypeCard(category, body, ingredient)
      :addClass('recipe_body_cooking_types')
    return
  end
end


     renderCookingTypeRequirement(category, typeBox, amountText, ingredient.types)
local function renderKitchenwareIcon(body, kitchenware)
  body:tag('div')
    :addClass('recipe_body_icon')
    :addClass('recipe_body_kitchenware_icon')
     :wikitext('[[File:Icon_' .. kitchenware .. '.png|35x35px|link=' .. kitchenware .. ']]')
end


local function renderKitchenwareMiniCard(category, body, kitchenware)
  body:tag('div')
    :addClass('recipe_body_icon')
    :addClass('recipe_body_kitchenware_card')
    :node(addMiniCard(category, kitchenware, ''))
end
local function renderCookingYield(args, category, body)
  if args[param.sYieldArg] == '0' then
     return
     return
   end
   end
end


local function renderKitchenware(category, body, args)
  local sYield = args[param.sYieldArg] or '1'
  local pageTitle = args.page or mw.title.getCurrentTitle().text
   local kitchenware = getKitchenware(args)
   local kitchenware = getKitchenware(args)
  local yieldCard = Card._main({
    name = pageTitle,
    text = sYield,
    show_caption = '1',
  })


   if #kitchenware == 0 then
   if #kitchenware == 0 then
     return
     body:tag('div')
      :addClass('recipe_body_icon')
      :wikitext('➜')
  elseif #kitchenware == 1 then
    -- Default: icon mode.
    -- Change this to renderKitchenwareMiniCard(category, body, kitchenware[1])
    -- if you prefer mini-card kitchenware display.
    renderKitchenwareIcon(body, kitchenware[1])
 
    category:wikitext('[[Category:Uses ', kitchenware[1], ']]')
  else
    local wrapper = body:tag('div')
      :addClass('recipe_body_icon')
      :addClass('recipe_body_kitchenware_multi')
 
    for _, itemName in ipairs(kitchenware) do
      wrapper:node(addMiniCard(category, itemName, ''))
    end
   end
   end


   local wrapper = body:tag('div')
   body:tag('div')
     :addClass('recipe_body_kitchenware')
     :addClass('recipe_body_yield')
    :node(yieldCard)


   wrapper:tag('div')
   local itemText = require('Module:Item').main{
    :addClass('recipe_body_kitchenware_label')
     [1] = pageTitle,
     :wikitext('Kitchenware')
     [2] = '15',
 
     x = sYield
  for _, itemName in ipairs(kitchenware) do
   }
     wrapper:node(addSimpleCard(itemName, ''))
     category:wikitext('[[Category:Uses ', itemName, ']]')
   end
end
end


Line 460: Line 533:
   end
   end


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


   body:done()
   body:done()
Line 484: Line 555:
     :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()