Module:OOO/Variants

Revision as of 20:01, 12 October 2025 by T-Bone (talk | contribs)

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

-- Module:OOO/Variants
-- Renders a right-aligned TabberNeue block of OOOInfoBox variants.
-- Usage examples:
--   {{OOOVariants|400162|400163|400113|400169|400170}}
--   {{OOOVariants | label1=2 m | art1=400162 | label2=3 m | art2=400163 | width=300 | align=left }}
--
-- Optional params (global):
--   |domain=Buildings   -- which data bucket to use; defaults to Buildings
--   |align=right        -- right (default), left, none, center
--   |width=300          -- pixels; applies to wrapper and each infobox
--
-- Optional per-tab overrides (append tab index N):
--   |labelN=..., |imageN=..., |descriptionN=..., |dimensionsN=..., |classN=...

local DATA = require('Module:OOO/Data')
local p = {}

-- keys we allow forwarding to OOOInfoBox per tab (suffix with index)
local PASSTHROUGH = { 'image', 'description', 'dimensions', 'class' }

local function tostring_or_nil(v)
  if v == nil then return nil end
  return tostring(v)
end

-- Sanitize label for tab header (avoid raw '|' or '=' breaking tabber syntax)
local function safe_label(s)
  s = tostring(s or '')
  s = s:gsub('|', '|'):gsub('=', '=')
  return s
end

-- Resolve a nice label: explicit labelN > data.displayName > art id
local function label_for(domain, art, given)
  if given and given ~= '' then return given end
  local rec = DATA.get(domain, art) or {}
  return rec.displayName or tostring(art)
end

function p.tabs(frame)
  local parent = frame:getParent() or frame
  local args   = parent.args or {}

  local domain = tostring_or_nil(args.domain or args.type) or 'Buildings'
  local align  = tostring_or_nil(args.align) or 'right'
  local width  = tonumber(args.width) -- optional shared width for wrapper + infoboxes

  -- Build each tab
  local entries = {}
  local i = 1
  while true do
    local art = args['art'..i] or args[i]
    if not art then break end

    local label = label_for(domain, art, args['label'..i] or args['name'..i])

    -- Args passed to the underlying OOOInfoBox template
    local ibx = {
      art  = art,
      type = domain,
      align = align,
    }
    if width and width >= 240 and width <= 600 then
      ibx.width = width
    end
    for _, key in ipairs(PASSTHROUGH) do
      local v = args[key..i]
      if v and v ~= '' then ibx[key] = v end
    end

    local content = frame:expandTemplate{ title = 'OOOInfoBox', args = ibx }
    entries[#entries+1] = string.format('%s=\n%s\n', safe_label(label), content)

    i = i + 1
  end

  if #entries == 0 then
    return '<strong class="error">OOOVariants: no variants provided</strong>'
  end

  -- Build the TabberNeue tag (ensures the extension parses it, not raw text)
  local inner  = table.concat(entries, '|-|\n')
  local tabber = frame:extensionTag('tabber', inner)

  -- Wrap so tabs float with the infobox; mirror align/width
  local wrap = mw.html.create('div'):addClass('ooo-infobox-tabwrap')
  if align == 'left' then
    wrap:addClass('ooo-infobox-tabwrap--left')
  elseif align == 'none' then
    wrap:addClass('ooo-infobox-tabwrap--none')
  elseif align == 'center' then
    wrap:addClass('ooo-infobox-tabwrap--center')
  end
  if width and width >= 240 and width <= 600 then
    wrap:css('width', tostring(width) .. 'px')
  end
  wrap:wikitext(tabber)

  -- Attach wrapper TemplateStyles
  local html = tostring(wrap)
  html = html .. frame:extensionTag('templatestyles', '', { src = 'Template:OOOInfoBoxTabber/styles.css' })

  -- Optional debug comment (viewable in page source)
  if tostring(args.debug) == '1' then
    html = html .. string.format('<!-- OOOVariants: domain=%s, align=%s, width=%s, tabs=%d -->',
      domain, align, width or 'default', #entries)
  end

  return html
end

return p