Module:CharacterSkill

From Granblue Fantasy Wiki
Jump to navigation Jump to search

Documentation for this module may be created at Module:CharacterSkill/doc

local p = {}
local getArgs = require('Module:Arguments').getArgs

local function stripRefTags(wikitext)
  local w = wikitext:gsub("<ref%s[^>]*/>", "")
  w = w:gsub("<ref[^>]*>.-</ref>", "")
  return w
end

function findArg(needle, haystack)
  local pattern = '|'..needle..'='
  
  local startIndex = haystack:find(pattern, 0, true)
  if startIndex == nil then
    return 'Not Found'
  end
  startIndex = startIndex + pattern:len()
  
  local endIndex = haystack:find('\n|', startIndex, true)
  endIndex = endIndex - 1
  
  local result = haystack:sub(startIndex,endIndex)
  
  return mw.text.trim(result)
end

function splitByLineBreak(text, index)
  index = tonumber(index)
  text = text .. "<br />"   -- Add extra <br/> so we can capture last group

  local matches = {}
  for t in text.gmatch(text, "([^<]*)<br%s?/>") do
      matches[#matches + 1] = t
  end 
  
  return matches[index]
end

function p.newRenderSkill(frame)
  local args = getArgs(frame, {
    trim = true,
    removeBlanks = true,
  })
  return p._newRenderSkill(frame, args)
end

function p._newRenderSkill(frame, args)
  -- 1. Parse arguments
  local characterName = args[1] or args['page'] or false
  local skillIndex = args[2] or args['no'] or false

  -- Show alternative version of the skill in the same slot?
  -- e.g. Yuisis SK1
  local alternativeSkill = args['alt'] == "true"
  
  -- Show in 2 lines and bigger icon?
  local largeFormat = args['large'] == "true"
  
  -- Show character name and icon instead of skill?
  local showCharacter = args['char'] == "true"
  
  local hideIcon = args['icon'] == "false"
  local hideText = args['icononly'] == "true"
  local hideTooltip = args['tooltip'] == "false"
  
  assert(characterName, 'Parameter 1 (Character Name) missing');
  
  -- 2. Find skill
  local title = mw.title.new(characterName)
  local rawPage = title:getContent()
  
  local iconArg = 'a'..skillIndex..'_icon'
  local nameArg = 'a'..skillIndex..'_name'
  local effdescArg = 'a'..skillIndex..'_effdesc'
  local skillIcon = findArg(iconArg, rawPage)
  local skillName = findArg(nameArg, rawPage)
  local effdesc = findArg(effdescArg, rawPage)
  
  assert(skillIcon, 'Skill icon not found')
  assert(skillName, 'Skill name not found')
  assert(effdesc, 'Skill effect description not found')

  -- Split by linebreak and retrieve first match and trim
  skillName = splitByLineBreak(skillName, 1)
  
  -- 3. Render into HTML
  local iconSize = largeFormat and '50px' or '25px'
  local alternativeSkillIndex = alternativeSkill and 2 or 1
  
  altSkillName = mw.text.split(skillName, '/', true)[alternativeSkillIndex]
  skillName = not altSkillName and skillName or altSkillName
  skillName = mw.text.trim(skillName)
  
  altSkillIcon = mw.text.split(skillIcon, ',', true)[alternativeSkillIndex]
  skillIcon = not altSkillIcon and skillIcon or altSkillIcon

  -- 3.1. Icon
  local icon = {''}
  if not hideIcon then
    local fileName = showCharacter and characterName .. ' square.jpg' or skillIcon
    table.insert(icon, '[[File:' .. fileName .. '|' .. iconSize .. '|' .. 'link=' .. characterName .. ']]')
    
    if largeFormat then
      table.insert(icon, '<br />')
    end
    
    if not hideText then
      table.insert(icon, '&nbsp;')
    end
  end
  icon = table.concat(icon)
  
  if hideText then
    return icon
  end
  
  -- 3.2. Tooltip text
  local name = showCharacter and characterName or skillName
  local tt = not hideText and '[[' .. characterName .. '|' .. name .. ']]' or ''
  
  -- 3.3. Tooltip content
  local tc = frame:preprocess(stripRefTags(effdesc))
  
  -- 3.4. Wrapping elements
  local res = {''}
  table.insert(res, icon)
  
  if not hideTooltip then
    table.insert(res, '<span class="image_link"><span class="tooltip">' .. tt .. '<span class="tooltiptext">' .. tc .. '</span></span></span>')
  else
    table.insert(res, tt)
  end

  return table.concat(res)
end

function p.renderSkill(frame)
  mw.log('Module:CharacterSkill: render start: ' .. os.clock())
  local template = frame.args.template
  local characterName = frame.args.characterName
  local skillIndex = frame.args.skillIndex
  local additionalArgs = frame.args.additionalArgs

  mw.log('Module:CharacterSkill: load data for '..characterName..' skill '..skillIndex..': ' .. os.clock())
  local title = mw.title.new(characterName)
  local rawPage = title:getContent()
  
  mw.log('Module:CharacterSkill: find args:' .. os.clock())
  local iconArg = 'a'..skillIndex..'_icon'
  local nameArg = 'a'..skillIndex..'_name'
  local effdescArg = 'a'..skillIndex..'_effdesc'
  local icon = findArg(iconArg, rawPage)
  local name = findArg(nameArg, rawPage)
  name = mw.text.trim(splitByLineBreak(name, 1))         -- Split by linebreak and retrieve first match and trim
  
  local effdesc = findArg(effdescArg, rawPage)

  mw.log('Module:CharacterSkill: expandTemplate')
  local args = {}
  args['link'] = characterName
  args['name'] = name
  args['icon'] = icon
  args['effdesc'] = frame:preprocess(stripRefTags(effdesc))

  -- Pass `frame.args.additionalArgs` to `args`
  if additionalArgs ~= nil then
    for arg in (additionalArgs):gmatch('[^;]+') do
      local i = arg:find('=')
      args[arg:sub(0, i-1)] = arg:sub(i+1)
    end
  end

  mw.log('Module:CharacterSkill: done: ' .. os.clock())
  return frame:expandTemplate{ title = template, args = args }
end

function p.testRender()
  local frame = mw.getCurrentFrame()
  frame.args.page = 'Threo'
  frame.args.no = '1'
  frame.args.alt = 'true'
  -- frame.args.tooltip = 'false'
  -- frame.args.icononly = 'true'
  return p.newRenderSkill(frame)
end

function p.testOldRender()
  local frame = mw.getCurrentFrame()
  frame.args.template = 'CharacterSkill/Template'
  frame.args.characterName = 'Ghandagoza'
  frame.args.skillIndex = '1'
  return p.renderSkill(frame)
end

function p.testSplit()
  local text = "foo<br/>bar<br />baz"
  mw.log(1, splitByLineBreak(text, 1))
  mw.log(2, splitByLineBreak(text, 2))
  mw.log(3, splitByLineBreak(text, 3))
  return
end

return p