Module:Recipe: Difference between revisions

No edit summary
No edit summary
Line 30: Line 30:
     sOut = sOut .. 's'
     sOut = sOut .. 's'
   end
   end
   return sOut
   return sOut
end
end


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


local function joinDisplay(list, separator)
local function addUseCategory(category, name, sort)
   local out = {}
   if not name or tostring(name) == '' then
    return
  end


   for _, value in ipairs(list) do
   if sort then
     table.insert(out, '[[' .. value .. ']]')
    category:wikitext('[[Category:Uses ', name, '|', sort, ']]')
  else
     category:wikitext('[[Category:Uses ', name, ']]')
   end
   end
  return table.concat(out, separator or ' / ')
end
end


local function joinFileNameParts(list)
local function getCurrentPageName(args)
   return table.concat(list, ' & ')
   return args[param.sPage] or args.page or mw.title.getCurrentTitle().text
end
end


Line 59: Line 62:
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


local function addRecipe(category, sAmt, sName, quality)
local function addRecipeCard(category, sAmt, sName, quality)
   local cardArgs = {
   local cardArgs = {
     name = sName,
     name = sName,
Line 73: Line 76:
   local cardNode = Card._main(cardArgs)
   local cardNode = Card._main(cardArgs)


   category:wikitext(
   addUseCategory(
     '[[Category:Uses ',
     category,
     sName,
     sName,
    '|',
     padLeft(tostring(sAmt or ''):gsub('%D', ''), 10)
     padLeft(tostring(sAmt or ''):gsub('%D', ''), 10),
    ']]'
   )
   )


Line 99: Line 100:
   local cardNode = Card._main(cardArgs)
   local cardNode = Card._main(cardArgs)


   if category and sName then
   addUseCategory(category, sName)
    category:wikitext('[[Category:Uses ', sName, ']]')
  end


   return cardNode
   return cardNode
end
local function addYieldCard(pageTitle, sYield)
  return Card._main({
    name = pageTitle,
    text = sYield,
    show_caption = '1'
  })
end
end


Line 112: Line 119:
local function renderHeader(args, output, category)
local function renderHeader(args, output, category)
   local header = output:tag('div'):addClass('recipe_header')
   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')
    -- Preserved from original module
     :tag('span'):addClass('mobileHide'):wikitext('<big>' .. sType .. '</big>'):done()
     :tag('span'):addClass('mobileHide'):wikitext('<big>' .. sType .. '</big>'):done()
     :tag('span'):addClass('mobileHide'):wikitext('<big>' .. sType .. '</big>'):done()
     :tag('span'):addClass('mobileHide'):wikitext('<big>' .. sType .. '</big>'):done()
Line 224: Line 231:
-- Standard recipe rendering
-- 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)
local function renderStandardYield(args, body)
Line 231: Line 248:


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


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


   body
   body
Line 244: Line 257:
     :tag('div'):addClass('recipe_body_yield')
     :tag('div'):addClass('recipe_body_yield')
       :node(yieldCard)
       :node(yieldCard)
  local itemText = require('Module:Item').main{
    [1] = pageTitle,
    [2] = '15',
    x = sYield
  }
end
end


Line 268: Line 275:
   end
   end


  -- Process sort parameter.
   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(addRecipe(category, args[sKey], sKey))
       body:node(addRecipeCard(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
    local restricted = false
     if tArgsProcessed[sKey] ~= true and not isRestrictedStandardParam(sKey) then
 
       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
Line 295: Line 296:


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Cooking recipe parsing
-- 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 function getCookingIngredient(args, index)
Line 310: Line 328:
   }
   }


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


  -- Multiple accepted 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 324: Line 344:
   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 334: Line 355:


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


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Cooking recipe display
-- Cooking display
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


local function renderCookingTypeCard(category, body, ingredient)
local function renderCookingSpecificItem(category, body, ingredient)
  body:node(addRecipeCard(
    category,
    ingredient.amount,
    ingredient.item,
    ingredient.quality
  ))
end
 
local function renderCookingTypeCards(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_card')
     :addClass('recipe_body_cooking_type_cards')
 
  local fileBase = joinFileNameParts(ingredient.types)
  local fileName = 'Recipe ' .. fileBase .. ' Icon.png'
  local caption = joinDisplay(ingredient.types, ' / ')


   for _, typeName in ipairs(ingredient.types) do
   for _, typeName in ipairs(ingredient.types) do
     category:wikitext('[[Category:Uses ', typeName, ']]')
     wrapper:node(addMiniCard(
  end
      category,
 
      typeName,
  local amountText = tostring(ingredient.amount or '1')
      ingredient.amount,
 
      ingredient.quality
  local card = wrapper:tag('div')
     ))
    :addClass('card')
    :addClass('recipe-type-card')
 
  if ingredient.quality then
    card:addClass('card-quality-' .. normalizeType(ingredient.quality))
  end
 
  card:tag('div')
    :addClass('card-image')
    :wikitext('[[File:' .. fileName .. '|64x64px|link=]]')
 
  card:tag('div')
    :addClass('card-caption')
    :wikitext(caption)
 
  if amountText ~= '' then
     card:tag('div')
      :addClass('card-text')
      :wikitext(amountText)
   end
   end
end
end
Line 407: Line 414:
   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')
     :addClass('recipe_body_cooking_option_cards')


   for _, itemName in ipairs(ingredient.options) do
   for _, itemName in ipairs(ingredient.options) do
     wrapper:node(addRecipe(category, ingredient.amount, itemName, ingredient.quality))
     wrapper:node(addMiniCard(
      category,
      itemName,
      ingredient.amount,
      ingredient.quality
    ))
   end
   end
end
end
Line 418: Line 430:
   -- |item_1 = Rice
   -- |item_1 = Rice
   if ingredient.item then
   if ingredient.item then
     body:node(addRecipe(category, ingredient.amount, ingredient.item, ingredient.quality))
     renderCookingSpecificItem(category, body, ingredient)
     return
     return
   end
   end
Line 435: Line 447:
   -- |item_1_type_2 = Saltwater Fish
   -- |item_1_type_2 = Saltwater Fish
   if #ingredient.types > 0 then
   if #ingredient.types > 0 then
     renderCookingTypeCard(category, body, ingredient)
     renderCookingTypeCards(category, body, ingredient)
     return
     return
   end
   end
end
end


local function renderKitchenwareIcon(body, kitchenware)
local function renderKitchenwareSlot(category, body, args)
   body:tag('div')
  local kitchenware = getKitchenware(args)
 
  if #kitchenware == 0 then
    body:tag('div')
      :addClass('recipe_body_icon')
      :wikitext('➜')
 
    return
  end
 
   local wrapper = body:tag('div')
     :addClass('recipe_body_icon')
     :addClass('recipe_body_icon')
     :addClass('recipe_body_kitchenware_icon')
     :addClass('recipe_body_kitchenware_cards')
    :wikitext('[[File:' .. kitchenware .. '_Icon.png|35x35px|link=' .. kitchenware .. ']]')
end


local function renderKitchenwareMiniCard(category, body, kitchenware)
  for _, kitchenwareName in ipairs(kitchenware) do
  body:tag('div')
     wrapper:node(addMiniCard(
    :addClass('recipe_body_icon')
      category,
    :addClass('recipe_body_kitchenware_card')
      kitchenwareName,
     :node(addMiniCard(category, kitchenware, ''))
      '',
      nil
    ))
  end
end
end


Line 460: Line 483:


   local sYield = args[param.sYieldArg] or '1'
   local sYield = args[param.sYieldArg] or '1'
   local pageTitle = args.page or mw.title.getCurrentTitle().text
   local pageTitle = getCurrentPageName(args)
  local kitchenware = getKitchenware(args)
 
  local yieldCard = Card._main({
    name = pageTitle,
    text = sYield,
    show_caption = '1',
  })
 
  if #kitchenware == 0 then
    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])
    renderKitchenwareMiniCard(category, body, kitchenware[1])


    category:wikitext('[[Category:Uses ', kitchenware[1], ']]')
   local yieldCard = addYieldCard(pageTitle, sYield)
   else
    local wrapper = body:tag('div')
      :addClass('recipe_body_icon')
      :addClass('recipe_body_kitchenware_multi')


    for _, itemName in ipairs(kitchenware) do
  renderKitchenwareSlot(category, body, args)
      wrapper:node(addMiniCard(category, itemName, ''))
    end
  end


   body:tag('div')
   body:tag('div')
     :addClass('recipe_body_yield')
     :addClass('recipe_body_yield')
     :node(yieldCard)
     :node(yieldCard)
  local itemText = require('Module:Item').main{
    [1] = pageTitle,
    [2] = '15',
    x = sYield
  }
end
end


Line 512: Line 504:
     :addClass('recipe_body_cooking')
     :addClass('recipe_body_cooking')


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


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


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


Line 556: Line 544:
     :addClass('recipe_container')
     :addClass('recipe_container')


  -- Must be local per render.
  -- Keeping this global can cause category leakage between recipe calls.
   local category = mw.html.create()
   local category = mw.html.create()


Line 565: Line 555:
     local sType = args[param.sTypeArg]
     local sType = args[param.sTypeArg]


     if normalizeType(sType) == 'cooking' then
     if normalizeText(sType) == 'cooking' then
       renderCookingRecipe(args, frame, output, category)
       renderCookingRecipe(args, frame, output, category)
     else
     else