Module:Card: Difference between revisions

ReisuDesign (talk | contribs)
No edit summary
No edit summary
 
(38 intermediate revisions by 4 users not shown)
Line 1: Line 1:
local p = {}
local p = {}
local lib = require('Module:Feature')
local lib = require('Module:Feature')
local LL = require('Module:Link label')._main
local ne = lib.isNotEmpty
local Ilib = require('Module:Icon')
local TemplateData = require('Module:TemplateData')
local array = require('Module:Array')
local CentralData = require('Module:CentralData')
 
local allData = CentralData.dataSheets
 
local CARD_ARGS = {
{
name = 'name',
alias = 1,
default = 'Unknown',
},
{
name = 'label',
alias = {2, 'text', 'count', 'amount', 'x'},
},
{
name = 'show_label',
alias = 'show_text',
type = '1',
},
{
name = 'quality',
alias = 'rarity',
default = 'Common',
},
{
name = 'type',
},
{
name = 'split',
},
{
name = 'suffix',
default = '',
},
{
name = 'image',
},
{
name = 'image_size',
alias = {'imageSize', 'size'},
},
{
name = 'image_ext',
alias = {'imageExt', 'ext', 'extension'},
default = 'png',
},
{
name = 'link',
},
{
name = 'link_suffix',
default = '',
},
{
name = 'no_link',
type = '1',
},
{
name = 'caption',
},
{
name = 'show_caption',
type = '1',
},
{
name = 'caption_width',
alias = 'captionWidth',
},
{
name = 'mini',
type = '1',
},
{
name = 'first',
type = '1',
},
{
name = 'up',
alias = 'UP',
type = '1',
},
{
name = 'notice',
},
}


function p.main(frame)
function p.main(frame)
local args = require('Module:Arguments').getArgs(frame, {
local args = require('Module:Arguments').getArgs(frame, {
parentFirst = true,
wrapper = {'Template:Card'},
removeBlanks = false,
parentOnly = false
wrapper = { 'Template:Card' }
})
})
return p._main(args)
return p._main(args)
end
local function getDataByName(dataType, dataTable, name)
local data = dataTable[name]
if data then
return data
end
local normalizedType = tostring(dataType or ''):lower()
if normalizedType == 'neighbor' or normalizedType == 'neighbors' then
return nil
end
for quality, names in pairs(dataTable) do
if type(names) == 'table' then
for _, itemName in ipairs(names) do
if itemName == name then
return {
quality = quality
}
end
end
end
end
return nil
end
function p.getTypeAndData(name, requestedType)
local img_type = requestedType or 'Item'
local img_data = nil
for _, v in ipairs(allData) do
local dataType = v[1]
local dataTable = v[2]
if lib.isEmpty(requestedType) or dataType == requestedType then
local data = getDataByName(dataType, dataTable, name)
if data then
img_type = dataType
img_data = data
break
end
end
end
return img_type, img_data
end
local function normalizeBool(value)
return value == true or value == '1' or value == 1 or value == 'yes'
end
local function normalizeClassName(value)
return tostring(value or '')
:lower()
:gsub('%s+', '-')
end
local function normalizeQuality(quality)
quality = tostring(quality or '')
if quality:find(';', 1, true) then
quality = array._main({
quality,
';',
firstItemOnly = 1
})
end
if lib.isEmpty(quality) then
quality = 'Common'
end
return normalizeClassName(quality)
end
local function stripLinkPrefix(value)
value = tostring(value or '')
-- Converts "Luca: Myriad Meadows" to "Myriad Meadows".
return mw.text.trim(value:gsub('^.-:%s*', '', 1))
end
local function setCaptionWidth(node, width)
if width == 'auto' or lib.isEmpty(width) then
node:addClass('auto-width')
else
node:css('width', width)
end
end
-- Generates the second icon for a split card.
local function makeSplitIcon(name, mini)
name = tostring(name or '')
local size = mini and 74 or 56
return '[[File:' ..
lib.sanitizeFileName(name) ..
' Icon.png|' ..
size .. 'x' .. size ..
'px|link=' ..
name ..
']]'
end
function p._processArgs(args)
local out = TemplateData.processArgs(args, CARD_ARGS)
-- Basic identity
out.name = out.name or 'Unknown'
out.split = out.split or ''
-- Use only a manually supplied type for lookup.
local requestedType = out.nonDefaults
and out.nonDefaults.type
or nil
out.type, out.data = p.getTypeAndData(
out.name,
requestedType
)
-- Base name for assets.
-- Removes a trailing disambiguation such as "(Currency)".
out.image_name = out.name--:gsub('%s*%([^()]*%)$', '')
-- Boolean parameters
out.mini = normalizeBool(out.mini)
out.first = normalizeBool(out.first)
out.up = normalizeBool(out.up)
out.no_link = normalizeBool(out.no_link)
out.show_label = normalizeBool(out.show_label)
out.show_caption = normalizeBool(out.show_caption)
-- Image defaults
out.suffix = out.suffix or ''
out.image_ext = out.image_ext or 'png'
if lib.isEmpty(out.image_size) then
out.image_size = out.mini and 48 or 70
end
if lib.isEmpty(out.suffix) then
out.suffix = ' Icon'
end
-- Data-driven defaults
if out.data then
if out.data.name then
out.defaults.label = out.data.name
out.defaults.caption = out.data.name
end
if out.data.title then
out.defaults.caption = out.data.title
end
if out.data.quality then
out.defaults.quality = out.data.quality
if not (out.nonDefaults and out.nonDefaults.quality) then
out.quality = out.data.quality
end
end
end
-- Quality / rarity
out.quality = normalizeQuality(out.quality)
-- Label handling
if out.show_label then
out.label = out.data
and (out.data.name or out.data.title)
or out.name
end
if out.label == '0' then
out.label = nil
end
-- Type-specific behavior
local lcType = tostring(out.type or ''):lower()
if lcType == 'neighbor' then
if lib.isEmpty(out.label) then
if out.mini and out.data and out.data.shortName then
out.label = out.data.shortName
elseif not out.mini then
out.label = out.name
end
end
if tonumber(out.image_size) then
out.image_size = tonumber(out.image_size) + 2
end
end
if lcType == 'redirect' then
out.defaults.link = stripLinkPrefix(out.name)
if not (out.nonDefaults and out.nonDefaults.link) then
out.link = stripLinkPrefix(out.name)
end
end
-- Caption defaults
if out.show_caption and lib.isEmpty(out.caption) then
if out.data then
out.caption = out.data.title
or out.data.name
or out.name
else
out.caption = out.name
end
end
-- Link handling
if out.link == nil then
out.link = lib.ternary(
out.name == 'Unknown',
'',
out.name
)
end
out.link_suffix = out.link_suffix or ''
out.final_link = out.link .. out.link_suffix
if out.no_link then
out.final_link = ''
end
-- Main image filename
if ne(out.image) then
out.final_file = out.image
else
out.final_file =
lib.sanitizeFileName(out.image_name) ..
out.suffix ..
'.' ..
out.image_ext
end
-- Main image wikitext
local linkPart = out.no_link
and '|link='
or ('|link=' .. out.final_link)
out.image_wikitext = table.concat({
'[[File:',
out.final_file,
'|',
out.image_size,
'px|alt=',
out.data and (out.data.name or out.data.title)
or out.name,
linkPart,
']]'
})
return out
end
end


function p._main(args)
function p._main(args)
local item = args.name or args[1]
local a = p._processArgs(args)
if not item then return mw.html.create() end -- if no input then return blank
local isSplit = ne(a.split)
local link = args.nolink and '' or (args.link or item)
 
local ext = args.ext or 'png'
-- Outer container
local amount = args.amount or args.x or args[2]
local node_container = mw.html.create('div')
local text = args.text or args[3]
:addClass('card-container')
local note = args.note
 
local nolink = args.nolink or false
if isSplit then
local notext = args.notext or false
node_container:addClass('card-split-card')
local quality = args.quality or args.q
end
-- mw.logObject(args)
 
local prefix = args.prefix or ''
if a.mini then
prefix = prefix:gsub('{space}', ' ')
node_container:addClass('mini-card')
local suffix = ' Icon' -- always append " Icon"
end
 
-- Wrapper and body
local node_card = node_container:tag('span')
:addClass('card-wrapper')
:tag('span')
:addClass('card-body')
 
-- Galaxy class on body
if not a.mini and ne(a.galaxy) then
node_card:addClass(
'card-galaxy-' .. normalizeClassName(a.galaxy)
)
end
 
-- Main image container
local imageContainer = node_card:tag('span')
:addClass('card-image-container')
:addClass('card-quality-' .. a.quality)
 
-- Split or regular image
if isSplit then
imageContainer:addClass('card-split-image')
 
-- First item: top-left half
imageContainer:tag('span')
:addClass('card-split-half')
:addClass('card-split-half-a')
:wikitext(a.image_wikitext)


-- Second item: bottom-right half
local card = mw.html.create():tag('div'):addClass('custom-card noborder')
imageContainer:tag('span')
local card_body = card:tag('div'):addClass('custom-card-body')
:addClass('card-split-half')
local card_image = card_body:tag('div'):addClass('custom-card-image')
:addClass('card-split-half-b')
local card_caption = card:tag('div'):addClass('custom-card-caption')
:wikitext(makeSplitIcon(a.split, a.mini))
else
-- main card image
imageContainer:wikitext(a.image_wikitext)
local filename = table.concat({prefix, item, suffix})
card_image:wikitext('[[File:', filename, '.', ext, '|51px|link=', link, ']]')
-- quality icon if valid
if quality then
card_body:addClass(' quality-' .. quality)
end
end
 
-- amount if any
-- Notice label
if lib.isNotEmpty(amount) then
if not a.mini and ne(a.notice) then
amount = tonumber(amount) ~= nil and lib.thousandsSeparator(amount) or amount
node_card:tag('span')
card_body:tag('div'):addClass('custom-card-amount'):wikitext(amount)
:addClass('card-notice-label')
:wikitext(a.notice)
end
end
 
-- default caption
-- First modifier
if args.show_caption then
if a.first then
card_caption:tag('br')
node_card:tag('span')
if link == '' then card_caption:wikitext(item)
:addClass('card-modifier')
elseif link == item then card_caption:wikitext(LL(item))
:addClass('card-modifier-first')
else card_caption:wikitext('[[', link, '|', item, ']]')
:wikitext(
end
'[[File:Icon Item First.png|x25px|link=|alt=First]]'
)
end
end
 
-- append custom text if any
-- UP modifier
if lib.isNotEmpty(text) then
if a.up then
card_caption:tag('br')
node_card:tag('span')
card_caption:wikitext(text)
:addClass('card-modifier')
:addClass('card-modifier-up')
:wikitext(
'[[File:Icon Item UP.png|x25px|link=|alt=UP]]'
)
end
end
 
-- ending note if any
-- Label below the image
if lib.isNotEmpty(note) then
if ne(a.label) then
card_caption:tag('br')
node_container:tag('span')
card_caption:tag('small'):wikitext('(', note, ')')
:addClass('card-label')
:wikitext(a.label)
end
end
 
-- mw.logObject(card) -- debug
-- Caption
return card
-- Split captions are opt-in and use spans instead of list items.
if a.show_caption and isSplit then
local node_caption = node_container:tag('span')
:addClass('card-caption')
:addClass('card-split-caption')
 
local list = node_caption:tag('span')
:addClass('card-split-caption-list')
 
list:tag('span')
:addClass('card-split-caption-item')
:wikitext('[[' .. a.name .. ']]')
 
list:tag('span')
:addClass('card-split-caption-item')
:wikitext('[[' .. a.split .. ']]')
 
setCaptionWidth(node_caption, a.caption_width)
 
elseif a.show_caption and ne(a.caption) then
local node_caption = node_container:tag('span')
:addClass('card-caption')
 
if a.no_link or lib.isEmpty(a.final_link) then
node_caption:wikitext(a.caption)
else
node_caption:wikitext(
'[[' .. a.final_link .. '|' .. a.caption .. ']]'
)
end
 
setCaptionWidth(node_caption, a.caption_width)
end
 
return tostring(node_container)
end
 
function p.templateData(frame)
return TemplateData.templateData(CARD_ARGS, {
description = 'Creates an item-style card with image, quality, label, split images, modifiers, and optional data-driven icons.',
format = 'inline'
}, frame)
end
 
function p.syntax(frame)
return TemplateData.syntax(CARD_ARGS, frame)
end
end


return p
return p