Module:Recipe: Difference between revisions

ReisuDesign (talk | contribs)
Created page with "local p = {} local Card = require('Module:Card') local category = mw.html.create() --Arguments for template local param = { sCharArg = 'character', sTypeArg = 'type', sSortArg = 'sort', sSortDelim = ';', --Needs to be pattern sSortDelim2 = '¤', sTimeArg = 'time', sYieldArg = 'yield', sPage = 'page' } p.param = param function padLeft(str, amt) return string.rep('0', amt - str:len()) .. str end function addRecipe(sAmt, sName) local cardNode = Card._m..."
 
No edit summary
 
(22 intermediate revisions by 2 users not shown)
Line 1: Line 1:
local p = {}
local p = {}
local Card = require('Module:Card')
local Card = require('Module:Card')
local category = mw.html.create()


--Arguments for template
-- Arguments for template
local param = {
local param = {
   sCharArg = 'character',
   sCharArg = 'character',
  sKitchArg = 'kitchenware',
   sTypeArg = 'type',
   sTypeArg = 'type',
   sSortArg = 'sort',
   sSortArg = 'sort',
   sSortDelim = ';', --Needs to be pattern
   sSortDelim = ';',
   sSortDelim2 = '¤',
   sSortDelim2 = '¤',
   sTimeArg = 'time',
   sTimeArg = 'time',
Line 14: Line 15:
   sPage = 'page'
   sPage = 'page'
}
}
p.param = param
p.param = param


function padLeft(str, amt)
--------------------------------------------------------------------------------
return string.rep('0', amt - str:len()) .. str
-- Utility
--------------------------------------------------------------------------------
 
local function padLeft(str, amt)
  str = tostring(str or '')
  return string.rep('0', math.max(amt - str:len(), 0)) .. str
end
end


function addRecipe(sAmt, sName)
local function pluralize(sOut, plural)
   local cardNode = Card._main({
  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, quality, sort)
if not name or tostring(name) == '' then
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'
  }
   })
 
   category:wikitext('[[Category:Uses ', sName, '|', padLeft(sAmt:gsub('%D', ''), 10), ']]')
  if quality then
     cardArgs.quality = quality
  end
 
   local cardNode = Card._main(cardArgs)
 
   addUseCategory(
    category,
    sName,
    quality,
    padLeft(tostring(sAmt or ''):gsub('%D', ''), 10)
  )
 
   return cardNode
   return cardNode
end
end


function pluralize(sOut,plural)
local function addMiniCard(category, sName, sText, quality)
   if plural then
  local cardArgs = {
     sOut = sOut .. 's'
    name = sName,
    text = sText or '',
    show_caption = '1',
    mini = '1'
  }
 
   if quality then
     cardArgs.quality = quality
   end
   end
   return sOut
 
  local cardNode = Card._main(cardArgs)
 
  addUseCategory(category, sName)
 
   return cardNode
end
end


function p.main(frame)
local function addYieldCard(pageTitle, sYield)
   local args = require('Module:Arguments').getArgs(frame, {
   return Card._main({
     parentFirst = true,
    name = pageTitle,
     wrapper = { 'Template:Recipe' }
     text = sYield,
     show_caption = '1'
   })
   })
  return p._main(args,frame)
end
end


function p._main(args,frame)
--------------------------------------------------------------------------------
   local output = mw.html.create('div')
-- Header rendering
    :addClass('new_genshin_recipe_container')
--------------------------------------------------------------------------------
   if type(args[param.sTypeArg]) ~= 'string' then
 
     output:tag('span'):addClass('error'):wikitext('Recipe type error. Must include recipe type.')
local function renderHeader(args, output, category)
   else
   local header = output:tag('div'):addClass('recipe-header')
     local tArgsProcessed = {}
   local sType = args[param.sTypeArg]
    local header = output:tag('div'):addClass('new_genshin_recipe_header')
 
  header:tag('span'):addClass('recipe-header-main')
     :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


     --Type Parse
     if n2 ~= '' then
    local sType = args[param.sTypeArg]
       table.insert(tTime, n2)
    header:tag('span'):addClass('new_genshin_recipe_header_main')
      -- Mobile Icon
       :tag('span'):addClass('mobileHide'):wikitext('[[File:Icon_' .. sType .. '_Small.png|15x15px|link=' .. sType .. '|alt=Icon_' .. sType .. '_Small.png]]'):done()
      -- Desktop Icon
      :tag('span'):addClass('hidden'):wikitext('[[File:Icon_' .. sType .. '_Small.png|37x37px|link=' .. sType .. '|alt=Icon_' .. sType .. '_Small.png]]'):done()
      -- Text
      :tag('span'):addClass('new_genshin_recipe_header_text'):wikitext('[[' ..  sType .. ']]'):done()
    category:wikitext('[[Category:' .. sType .. ']]')


    --Time Parse
       if n2 ~= '1' then
    if type(args[param.sTimeArg]) == 'string' then
        plural = true
       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) --insert first value definitely
          if n1 ~= '1' then
              plural = true --generate plural
          end
          if d == 'd' then
              table.insert(tTime, pluralize('day', plural))
              plural = false --consume plural
              key = true
          end
          if n2 ~= '' then
              table.insert(tTime, n2)
              if n2 ~= '1' then
                  plural = true --generate plural
              end
          end
          if h == 'h' then
              table.insert(tTime,pluralize('hour', plural))
              plural = false --consume plural
              key = true
          end
          if n3 ~= '' then
              table.insert(tTime, n3)
              if n3 ~= '1' then
                  plural = true --generate plural
              end
          end
          if m == 'm' then
              table.insert(tTime, pluralize('minute', plural))
              plural = false --consume plural
              key = true
          end
          if n4 ~= '' then
              table.insert(tTime, n4)
              if n4 ~= '1' then
                  plural = true --generate plural
              end
          end
          if s == 's' then
              table.insert(tTime, pluralize('second', plural))
              key = true
          end
       end
       end
      if not(key) then
    end
          table.insert(tTime,pluralize('minute', plural))
 
    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
       local sTime = ''
    end
       for _, each in ipairs(tTime) do
 
          sTime = sTime .. each .. ' '
    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
      header:tag('span'):addClass('new_genshin_recipe_header_sub')
        :tag('span'):addClass('mobileHide'):wikitext(' for '):done()
        :tag('span'):addClass('hidden'):wikitext('[[File:Icon Clock.png|24x24px|link=Time]]'):done()
        :tag('span'):addClass('new_genshin_recipe_header_text'):wikitext(sTime):done()
     end
     end
     --Character Parse
 
     if type(args[param.sCharArg]) == 'string' then
    if s == 's' then
      local sCharName = args[param.sCharArg]
      table.insert(tTime, pluralize('second', plural))
      header:tag('span'):addClass('new_genshin_recipe_header_sub')
      key = true
        :tag('span'):addClass('mobileHide'):wikitext(' with '):done()
    end
        :tag('span'):addClass('hidden'):wikitext('[[File:' .. sCharName .. ' Icon.png|24x24px|link=' .. sCharName .. ']]'):done()
  end
        :tag('span'):addClass('new_genshin_recipe_header_text'):wikitext('[[' .. sCharName .. ']]'):done()
 
  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'):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'):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'):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 nil
  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
  end


local body = output:tag('div'):addClass('new_genshin_recipe_body')
  renderStandardYield(args, body)


--Check if sSortDelim2 exists in sSortArg
  body:done()
if ((args[param.sSortArg] or ''):find(param.sSortDelim2) ~= nil) then
end
param.sSortDelim = param.sSortDelim2
 
end
--------------------------------------------------------------------------------
-- Cooking parsing
    --Process Sort Parameter (Split by Delimiter)
--------------------------------------------------------------------------------
    for sKey in string.gmatch(args[param.sSortArg] or '', '([^' .. param.sSortDelim .. ']+)') do
 
      if type(args[sKey]) ~= 'nil' then
local function getMaxCookingItemIndex(args)
        body:node(addRecipe(args[sKey], sKey))
  local maxIndex = 0
         tArgsProcessed[sKey] = true
 
  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
     end
  end


     --Process Rest of Unrestricted Parameters
  return maxIndex
    for sKey,sVal in pairs(args) do
end
      --Check if restricted parameter
 
       local restricted = false
local function getCookingIngredient(args, index)
      for _, keyParam in pairs(param) do
  local prefix = 'item_' .. index
        if keyParam == sKey then
 
          restricted = true
  local ingredient = {
        end
     index = index,
      end
    amount = args[prefix .. '_amount'] or nil,
      --If not processed, and not a restricted parameter
    quality = args[prefix .. '_quality'],
       if tArgsProcessed[sKey] ~= true and not(restricted) then
    item = args[prefix],
        body:node(addRecipe(sVal, sKey))
    types = {},
       end
    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 or 'Gray')
 
  local container = body:tag('span')
    :addClass('card-container')
    :addClass('recipe-type-split-card')
 
  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 qualityClass then
    imageContainer:addClass(qualityClass)
end
 
  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 nil
  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
  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()


    --Yield Parse
  if type(args[param.sTypeArg]) ~= 'string' then
    if args[param.sYieldArg] ~= '0' then
    output:tag('span')
    local sYield = args[param.sYieldArg] or '1'
      :addClass('error')
    local pageTitle = args.page or mw.title.getCurrentTitle().text
      :wikitext('Recipe type error. Must include recipe type.')
    local yieldCard = Card._main{
  else
      name = pageTitle,
    local sType = args[param.sTypeArg]
      text = sYield,
 
      show_caption = '1',
    if normalizeText(sType) == 'cooking' then
    }
      renderCookingRecipe(args, frame, output, category)
    body
    else
      :tag('div'):addClass('new_genshin_recipe_body_icon')
      renderStandardRecipe(args, frame, output, category)
        :wikitext('[[File:Icon_' .. sType .. '_Recipe.png|35x35px|link=' .. sType .. ']]'):done()
      :tag('div'):addClass('new_genshin_recipe_body_yield')
        :node(yieldCard)
       
    local itemText = require('Module:Item').main{
    [1] = pageTitle,
    [2] = '15',
    x = sYield
    }
   
     end
     end
    body:done()
   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