• Welcome to Touhou Wiki!
  • Registering is temporarily disabled. Check in our Discord server to request an account and for assistance of any kind.

Module:Navbox

From Touhou Wiki
Revision as of 22:32, 28 September 2012 by DennouNeko (talk | contribs) (temporarily switching to mw-collapsible)
Jump to navigation Jump to search

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

-- lua port of [[Template:Navbox]]
-- by DennouNeko

-- constants
local colors = {
  game = {title = '#FFC9C2', above = '#FFD1CA', group = '#FFD9D2', subgroup = '#FFE1DA', dark = '#FFEEE8', background = '#FFF4EE'};
  music = {title = '#FFF3B4', above = '#FFF6C0', group = '#FFF7C8', subgroup = '#FFF8D0', dark = '#FFFBE4', background = '#FFFBEE'};
  printwork = {title = '#DDE6FF', above = '#E1E7FF', group = '#E6E9FF', subgroup = '#EAECFF', dark = '#EDF2FF', background = '#F4F9FF'}
}

-- helper functions
require("Module:Common")

local function addstyle(tbl, val)
  if isset(val) then
    local av = trim(val)
    if string.sub(av, -1) ~= ';' then av = av .. ';' end
    table.insert(tbl, av)
  end
end

local function scan_lists(frame)
  local idx = {}
  local list = {}
  local group = {}
  local liststyle = {}
  local groupstyle = {}

  local ret = {}

  for k,v in frame:argumentPairs() do
    if string.sub(k, 1, 5) == 'group' then
      if string.sub(k, -5) == 'style' then
        k1 = tonumber(string.sub(k, 6, -6))
        if k1 ~= nil then groupstyle[k1] = v end
      else
        k1 = tonumber(string.sub(k, 6))
        if k1 ~= nil then group[k1] = v end
      end
    elseif string.sub(k, 1, 4) == 'list' then
      if string.sub(k, -5) == 'style' then
        k1 = tonumber(string.sub(k, 5, -6))
        if k1 ~= nil then liststyle[k1] = v end
      else
        k1 = tonumber(string.sub(k, 5))
        if k1 ~= nil then
          list[k1] = v
          -- only "list#" elements produce valid indexes
          table.insert(idx, k1)
        end
      end
    end
  end

  table.sort(idx)

  for k,v in ipairs(idx) do
    local tmp = {}
    tmp['index'] = v
    tmp['list'] = list[v]
    if isset(group[v]) then tmp['group'] = group[v] end
    if isset(liststyle[v]) then tmp['liststyle'] = liststyle[v] end
    if isset(groupstyle[v]) then tmp['groupstyle'] = groupstyle[v] end
    table.insert(ret, tmp)
  end

  return ret
end

-- functions that create the structure
local function start_box(frame, border, type)
  local ret = {""}
  if border == "subgroup" or border == "child" then
    table.insert(ret, '</div>')
  elseif border == "none" then
    -- nothing to do
  else
    table.insert(ret, '<table class="navbox')
    if isset(frame.args['bodyclass']) then table.insert(ret, " " .. frame.args['bodyclass']) end
    table.insert(ret, '" cellspacing="0" style="')
    if isset(colors[type]) then table.insert(ret, 'background:' .. colors[type]['background'] .. ';') end
    table.insert(ret, 'border:1px solid #aaa; padding:1px;')
    table.insert(ret, 'width:100%;vertical-align:middle;margin:auto;clear:both;font-size:88%;text-align:center;')
    addstyle(ret, frame.args['bodystyle'])
    addstyle(ret, frame.args['style'])
    table.insert(ret, '"><tr><td style="padding: 2px;">')
  end

  table.insert(ret, '<table cellspacing="0" class="nowraplinks')
  if isset(frame.args['title']) and frame.args['state'] ~= "plain" and frame.args['state'] ~= "off" then
    --table.insert(ret, ' collapsible ')
    table.insert(ret, ' mw-collapsible ')
    if isset(frame.args['state']) then
      table.insert(ret, frame.args['state'])
    else
      --table.insert(ret, 'autocollapse')
      table.insert(ret, 'mw-collapsed')
    end
  end
  if border == "subgroup" or border == "child" or border == "none" then
    table.insert(ret, ' navbox-subgroup" style="')
    if isset(colors[type]) then table.insert(ret, 'background:' .. colors[type]['background'] .. ';') end
    table.insert(ret, 'margin:auto;clear:both;font-size:88%;text-align:center;')
    table.insert(ret, 'width:100%;vertical-align:middle;')
    addstyle(ret, frame.args['bodystyle'])
    addstyle(ret, frame.args['style'])
    table.insert(ret, '">')
  else
    table.insert(ret, '" style="width:100%;background:transparent;color:inherit;">')
  end

  return table.concat(ret)
end

local function end_box(frame, border, type)
  local ret = {""}
  table.insert(ret, '</table>')
  if border == "subgroup" or border == "child" then
    table.insert(ret, '<div>')
  elseif border == "none" then
    -- nothing to do
  else
    table.insert(ret, '</td></tr></table>')
  end
  return table.concat(ret)
end

local function build_title(frame, border, type)
  local ret = {""}
  if not isset(frame.args['title']) then return '' end

  table.insert(ret, '<tr>')
  if isset(frame.args['titlegroup']) then
    table.insert(ret, '<td class="navbox-group" style="')
    if isset(colors[type]) then table.insert(ret, 'background:' .. colors[type]['group'] .. ';') end
    table.insert(ret, 'padding-left:1em;padding-right:1em;white-space:nowrap;text-align:right;')
    addstyle(ret, frame.args['basestyle'])
    addstyle(ret, frame.args['groupstyle'])
    addstyle(ret, frame.args['titlegroupstyle'])
    table.insert(ret, '">')
    table.insert(ret, frame.args['titlegroup'])
    table.insert(ret, '</td>')

    table.insert(ret, '<th style="border-left:2px solid #fdfdfd;width:100%;')
  else
    table.insert(ret, '<th style="')
  end
  if isset(colors[type]) then table.insert(ret, 'background:' .. colors[type]['title'] .. ';') end
  table.insert(ret, 'text-align:center;')
  addstyle(ret, frame.args['basestyle'])
  addstyle(ret, frame.args['titlestyle'])
  table.insert(ret, '"')

  local cs = 2
  if isset(frame.args['imageleft']) then cs = cs + 1 end
  if isset(frame.args['image']) then cs = cs + 1 end
  if isset(frame.args['titlegroup']) then cs = cs - 1 end
  table.insert(ret, ' colspan = "' .. cs .. '"')

  table.insert(ret, ' class="navbox-title"')
  table.insert(ret, '>')

  if frame.args['navbar'] == "plain" or frame.args['navbar'] == "off" or border == "subgroup" or border == "child" or border == "none" then
    if frame.args['navbar'] == "off" then
      if frame.args['state'] == "plain" then table.insert(ret, '<div style="float:right;width:6em;">&nbsp;</div>') end
    else
      if frame.args['state'] ~= "plain" then table.insert(ret, '<div style="float:left; width:6em;text-align:left;">&nbsp;</div>') end
    end
  else
    if frame.args['state'] == "plain" then table.insert(ret, '<div style="float:right;width:6em;">&nbsp;</div>') end
    table.insert(ret, '<div style="float:left; width:6em;text-align:left;">')

    if frame.args['name'] ~= nil then
      local args = {}
      args[#args+1] = frame.args['name']

      local q = {""}
      table.insert(q, 'text-align:center;')
      addstyle(q, frame.args['basestyle'])
      addstyle(q, frame.args['titlestyle'])
      table.insert(q, 'border:none;')
      args['fontstyle'] = table.concat(q)

      args['mini'] = '1'

      table.insert(ret, frame:expandTemplate{title = 'Navbar', args = args})
    else
      table.insert(ret, '&nbsp;')
      table.insert(ret, '[[Category:Navboxes without name]]')
    end

    table.insert(ret, '</div>')
  end

  table.insert(ret, '<span')
  if isset(frame.args['titleclass']) then table.insert(ret, ' class="' .. frame.args['titleclass'] .. '"') end
  table.insert(ret, ' style="font-size:')
  if border == "subgroup" or border == "child" or border == "none" then
    table.insert(ret, '100%')
  else
    table.insert(ret, '110%')
  end
  table.insert(ret, ';">')

  table.insert(ret, frame.args['title'])

  table.insert(ret, '</span>')

  table.insert(ret, '</th></tr>')
  return table.concat(ret)
end

local function build_row(frame, k, group, list, groupstyle, liststyle, border, type)
  local ret = {""}
  if isset(group) then
    table.insert(ret, '<td class="navbox-group" style="')
    if border ~= "subgroup" and border ~= "child" then
      if isset(colors[type]) then table.insert(ret, 'background:' .. colors[type]['group'] .. ';') end
    else
      if isset(colors[type]) then table.insert(ret, 'background:' .. colors[type]['subgroup'] .. ';') end
    end
    table.insert(ret, 'padding-left:1em; padding-right:1em; white-space:nowrap; text-align:right;')
    addstyle(ret, frame.args['basestyle'])
    if isset(frame.args['groupwidth']) then table.insert(ret, 'width:' .. frame.args['groupwidth'] .. ';') end
    addstyle(ret, frame.args['groupstyle'])
    addstyle(ret, groupstyle)
    table.insert(ret, '"><div style="padding:0;">' .. group .. '</div></td>')
    table.insert(ret, '<td style="text-align:left;border-left-width:2px;border-left-style:solid;')
  else
    table.insert(ret, '<td colspan=2 style="')
  end
  -- a bit tricky, but it works as XOR
  if (frame.args['evenodd'] == "swap") ~= ((k % 2) == 0) then
    if isset(colors[type]) then table.insert(ret, 'background:' .. colors[type]['dark'] .. ';') end
  else
    table.insert(ret, 'background:transparent;')
  end
  
  if not isset(frame.args['groupwidth']) then table.insert(ret, 'width:100%;') end
  table.insert(ret, 'padding: 0;')
  addstyle(ret, frame.args['liststyle'])
  if (frame.args['evenodd'] == "swap") ~= ((k % 2) == 0) then
    addstyle(ret, frame.args['evenstyle'])
  else
    addstyle(ret, frame.args['oddstyle'])
  end
  addstyle(ret, liststyle)
  table.insert(ret, '" class="navbox-list')
  if (frame.args['evenodd'] == "swap") ~= ((k % 2) == 0) then
    table.insert(ret, ' navbox-even')
  else
    table.insert(ret, ' navbox-odd')
  end
  table.insert(ret, '">')

  table.insert(ret, '<div style="padding:')
  if isset(frame.args['list' .. k .. 'padding']) then
    table.insert(ret, frame.args['list' .. k .. 'padding'])
  elseif isset(frame.args['listpadding']) then
    table.insert(ret, frame.args['listpadding'])
  else
    table.insert(ret, '0em 0.25em')
  end
  table.insert(ret, ';">\n' .. list .. '</div>')
  table.insert(ret, '</td>')
  return table.concat(ret)
end

local function build_body(frame, border, type)
  local ret = {""}
  local sep = isset(frame.args['title'])

  local lists = scan_lists(frame)
  
  if isset(frame.args['above']) then
    if sep then
      table.insert(ret, '<tr style="height: 2px;"><td></td></tr>')
    end
    sep = true
    table.insert(ret, '<tr><td class="navbox-abovebelow" style="')
    if isset(colors[type]) then
      if border ~= "subgroup" and border ~= "child" then
        table.insert(ret, 'background:' .. colors[type]['above'] .. ';')
      else
        table.insert(ret, 'background:' .. colors[type]['group'] .. ';')
      end
    end
    table.insert(ret, 'padding-left:1em;padding-right:1em;text-align:center;')
    addstyle(ret, frame.args['basestyle'])
    addstyle(ret, frame.args['abovestyle'])
    table.insert(ret, '"')

    local cs = 2
    if isset(frame.args['imageleft']) then cs = cs + 1 end
    if isset(frame.args['image']) then cs = cs + 1 end
    table.insert(ret, ' colspan="' .. cs .. '"')
    table.insert(ret, '>' .. frame.args['above'] .. '</td></tr>')
  end

  local imgs = true
  local irows = 1
  if #lists > 0 then irows = 2 * #lists - 1 end

  for k,v in ipairs(lists) do
    if sep then
      table.insert(ret, '<tr style="height: 2px;"><td></td></tr>')
    end
    sep = true

    table.insert(ret, '<tr>')

    if imgs then
      if isset(frame.args['imageleft']) then
        table.insert(ret, '<td style="width:0%;padding:0px 2px 0px 0px;')
        addstyle(ret, frame.args['imageleftstyle'])
        table.insert(ret, '"')
        table.insert(ret, ' rowspan="' .. irows .. '"')
        table.insert(ret, '>' .. frame.args['imageleft'] .. '</td>')
      end
    end
    
    table.insert(ret, build_row(frame, v['index'], v['group'], v['list'], v['groupstyle'], v['liststyle'], border, type))

    if imgs then
      if isset(frame.args['image']) then
        table.insert(ret, '<td style="width:0%;padding:0px 2px 0px 0px;')
        addstyle(ret, frame.args['imagestyle'])
        table.insert(ret, '"')
        table.insert(ret, ' rowspan="' .. irows .. '"')
        table.insert(ret, '>' .. frame.args['image'] .. '</td>')
      end

      imgs = false
    end
    table.insert(ret, '</tr>')
  end

  if isset(frame.args['below']) then
    if sep then
      table.insert(ret, '<tr style="height: 2px;"><td></td></tr>')
    end
    sep = true
    table.insert(ret, '<tr><td class="navbox-abovebelow" style="')
    if isset(colors[type]) then
      if border ~= "subgroup" and border ~= "child" then
        table.insert(ret, 'background:' .. colors[type]['above'] .. ';')
      else
        table.insert(ret, 'background:' .. colors[type]['group'] .. ';')
      end
    end
    table.insert(ret, 'padding-left:1em;padding-right:1em;text-align:center;')
    addstyle(ret, frame.args['basestyle'])
    addstyle(ret, frame.args['belowstyle'])
    table.insert(ret, '"')

    local cs = 2
    if isset(frame.args['imageleft']) then cs = cs + 1 end
    if isset(frame.args['image']) then cs = cs + 1 end
    table.insert(ret, ' colspan="' .. cs .. '"')
    table.insert(ret, '>' .. frame.args['below'] .. '</td></tr>')
  end

  return table.concat(ret)
end

-- exported functions
local function buildNavbox(frame)
  local template = {""}
  local border = ""
  local type = ""

  if isset(frame.args['border']) then
    border = trim(frame.args['border'])
  elseif isset(frame.args[1]) then
    border = trim(frame.args[1])
  end

  if isset(frame.args['type']) then
    type = trim(frame.args['type'])
  end

  -- TODO: filtering of border and type values?

  table.insert(template, start_box(frame, border, type))
  table.insert(template, build_title(frame, border, type))
  table.insert(template, build_body(frame, border, type))
  table.insert(template, end_box(frame, border, type))

  return table.concat(template)
end

local function buildNavboxTemplate(frame)
  return buildNavbox(frame:getParent())
end

local function buildColorTable(frame)
  local ret = {""}
  table.insert(ret, '<table class="wikitable" style="text-align: center;">')
  table.insert(ret, '<caption>List of colors in order from darkest to brigthest one</caption>')
  table.insert(ret, '<tr><th>"type"</th><th>title</th><th>above, below</th><th>group,<br/>sub-above/below</th><th>sub-group</th><th>dark background</th><th>background</th></tr>')
  for k,v in pairs(colors) do
    table.insert(ret, '<tr>')
    table.insert(ret, '<td>' .. k .. '</td>')
    table.insert(ret, '<td style="background:' .. v['title'] .. '">' .. v['title'] .. '</td>')
    table.insert(ret, '<td style="background:' .. v['above'] .. '">' .. v['above'] .. '</td>')
    table.insert(ret, '<td style="background:' .. v['group'] .. '">' .. v['group'] .. '</td>')
    table.insert(ret, '<td style="background:' .. v['subgroup'] .. '">' .. v['subgroup'] .. '</td>')
    table.insert(ret, '<td style="background:' .. v['dark'] .. '">' .. v['dark'] .. '</td>')
    table.insert(ret, '<td style="background:' .. v['background'] .. '">' .. v['background'] .. '</td>')
    table.insert(ret, '</tr>')
  end
  table.insert(ret, '</table>')
  return table.concat(ret)
end

-- export local functions
return {
  ['buildNavbox'] = buildNavbox,
  ['buildNavboxTemplate'] = buildNavboxTemplate,
  ['buildColorTable'] = buildColorTable
}