Module:Card: Difference between revisions

No edit summary
No edit summary
 
(23 intermediate revisions by 4 users not shown)
Line 1: Line 1:
local p = {}
local p = {}


Line 5: Line 6:
local TemplateData = require('Module:TemplateData')
local TemplateData = require('Module:TemplateData')
local array = require('Module:Array')
local array = require('Module:Array')
local CentralData = require('Module:CentralData')


local allData = {
local allData = CentralData.dataSheets
-- {'Neighbor', mw.loadData('Module:CentralData/Neighbors')},
{'Creature', mw.loadData('Module:CentralData/Creatures')},
-- {'Furniture', mw.loadData('Module:CentralData/Furniture')},
{'Item', mw.loadData('Module:CentralData/Items')},
}


-- Minimal TemplateData args.
-- This does not need to be huge unless you want full documentation for every parameter.
local CARD_ARGS = {
local CARD_ARGS = {
{
{
Line 33: Line 28:
name = 'quality',
name = 'quality',
alias = 'rarity',
alias = 'rarity',
default = 'Gray',
default = 'Common',
},
},
{
{
name = 'type',
name = 'type',
default = 'Item',
},
{
name = 'split',
},
},
{
{
Line 48: Line 45:
{
{
name = 'image_size',
name = 'image_size',
alias = 'imageSize',
alias = {'imageSize', 'size'},
},
},
{
{
name = 'image_ext',
name = 'image_ext',
alias = {'imageExt', 'extension'},
alias = {'imageExt', 'ext', 'extension'},
default = 'png',
default = 'png',
},
},
Line 63: Line 60:
},
},
{
{
name = 'nolink',
name = 'no_link',
type = '1',
type = '1',
},
},
Line 89: Line 86:
alias = 'UP',
alias = 'UP',
type = '1',
type = '1',
},
{
name = 'galaxy',
},
},
{
{
Line 100: Line 94:
function p.main(frame)
function p.main(frame)
local args = require('Module:Arguments').getArgs(frame, {
local args = require('Module:Arguments').getArgs(frame, {
wrapper = { 'Template:Card' },
wrapper = {'Template:Card'},
parentOnly = false
parentOnly = false
})
})


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
end


Line 116: Line 137:


if lib.isEmpty(requestedType) or dataType == requestedType then
if lib.isEmpty(requestedType) or dataType == requestedType then
local data = dataTable[name]
local data = getDataByName(dataType, dataTable, name)


if data then
if data then
Line 151: Line 172:


if lib.isEmpty(quality) then
if lib.isEmpty(quality) then
quality = 'Gray'
quality = 'Common'
end
end


return normalizeClassName(quality)
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
end


Line 163: Line 191:
node:css('width', width)
node:css('width', width)
end
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
end


Line 170: Line 213:
-- Basic identity
-- Basic identity
out.name = out.name or 'Unknown'
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


-- Data lookup
out.type, out.data = p.getTypeAndData(
out.type, out.data = p.getTypeAndData(out.name, out.type)
out.name,
requestedType
)


-- Boolean-ish params
-- 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.mini = normalizeBool(out.mini)
out.first = normalizeBool(out.first)
out.first = normalizeBool(out.first)
out.up = normalizeBool(out.up)
out.up = normalizeBool(out.up)
out.nolink = normalizeBool(out.nolink)
out.no_link = normalizeBool(out.no_link)
out.show_label = normalizeBool(out.show_label)
out.show_label = normalizeBool(out.show_label)
out.show_caption = normalizeBool(out.show_caption)
out.show_caption = normalizeBool(out.show_caption)
Line 194: Line 249:
end
end


-- Data-driven name
-- Data-driven defaults
out.data_name = out.data and out.data.name or nil
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


-- Quality / rarity
if not (out.nonDefaults and out.nonDefaults.quality) then
if lib.isEmpty(out.quality) and out.data and out.data.quality then
out.quality = out.data.quality
out.quality = out.data.quality
end
end
end
end


-- Quality / rarity
out.quality = normalizeQuality(out.quality)
out.quality = normalizeQuality(out.quality)


-- Galaxy
-- Label handling
if lib.isEmpty(out.galaxy) and out.data and out.data.galaxy then
out.galaxy = out.data.galaxy
end
 
-- Label/text handling
if out.show_label then
if out.show_label then
out.label = out.data_name or out.name
out.label = out.data
and (out.data.name or out.data.title)
or out.name
end
end


Line 230: Line 295:
end
end


-- Account for transparent borders on neighbor icons
if tonumber(out.image_size) then
if tonumber(out.image_size) then
out.image_size = tonumber(out.image_size) + 2
out.image_size = tonumber(out.image_size) + 2
Line 236: Line 300:
end
end


-- Caption handling
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.show_caption and lib.isEmpty(out.caption) then
out.caption = out.data_name or out.name
if out.data then
out.caption = out.data.title
or out.data.name
or out.name
else
out.caption = out.name
end
end
end


-- Link handling
-- Link handling
if out.link == nil then
if out.link == nil then
out.link = lib.ternary(out.name == 'Unknown', '', out.name)
out.link = lib.ternary(
out.name == 'Unknown',
'',
out.name
)
end
end


Line 249: Line 331:
out.final_link = out.link .. out.link_suffix
out.final_link = out.link .. out.link_suffix


if out.nolink then
if out.no_link then
out.final_link = ''
out.final_link = ''
end
end


-- File name
-- Main image filename
if ne(out.image) then
if ne(out.image) then
out.final_file = out.image
out.final_file = out.image
else
else
out.final_file = lib.sanitizeFileName(out.name) .. out.suffix .. '.' .. out.image_ext
out.final_file =
lib.sanitizeFileName(out.image_name) ..
out.suffix ..
'.' ..
out.image_ext
end
end


-- Main image wikitext
-- Main image wikitext
local linkPart = out.nolink and '|link=' or ('|link=' .. out.final_link)
local linkPart = out.no_link
and '|link='
or ('|link=' .. out.final_link)


out.image_wikitext = table.concat({
out.image_wikitext = table.concat({
Line 269: Line 357:
out.image_size,
out.image_size,
'px|alt=',
'px|alt=',
out.name,
out.data and (out.data.name or out.data.title)
or out.name,
linkPart,
linkPart,
']]'
']]'
Line 279: Line 368:
function p._main(args)
function p._main(args)
local a = p._processArgs(args)
local a = p._processArgs(args)
local isSplit = ne(a.split)


-- Outer container
local node_container = mw.html.create('div')
local node_container = mw.html.create('div')
:addClass('card-container')
:addClass('card-container')
if isSplit then
node_container:addClass('card-split-card')
end


if a.mini then
if a.mini then
Line 287: Line 382:
end
end


-- Old-style wrapper/body structure.
-- Wrapper and body
-- This is usually important if your existing CSS was written for the old Card module.
local node_card = node_container:tag('span')
local node_card = node_container:tag('span')
:addClass('card-wrapper')
:addClass('card-wrapper')
:tag('span')
:tag('span')
:addClass('card-body')
: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
-- Main image container
node_card:tag('span')
local imageContainer = node_card:tag('span')
:addClass('card-image-container')
:addClass('card-image-container')
:addClass('card-quality-' .. a.quality)
:addClass('card-quality-' .. a.quality)
:wikitext(a.image_wikitext)


-- Galaxy icon
-- Split or regular image
if not a.mini and ne(a.galaxy) then
if isSplit then
node_card:addClass('card-galaxy-' .. normalizeClassName(a.galaxy))
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)


node_card:tag('span')
-- Second item: bottom-right half
:addClass('card-icon-galaxy')
imageContainer:tag('span')
:wikitext(
:addClass('card-split-half')
'[[File:Icon ' ..
:addClass('card-split-half-b')
a.galaxy ..
:wikitext(makeSplitIcon(a.split, a.mini))
'.png|alt=' ..
else
a.galaxy ..
imageContainer:wikitext(a.image_wikitext)
'|link=' ..
a.galaxy ..
'|20px]]'
)
end
end


Line 329: Line 431:
:addClass('card-modifier')
:addClass('card-modifier')
:addClass('card-modifier-first')
:addClass('card-modifier-first')
:wikitext('[[File:Icon Item First.png|x25px|link=|alt=First]]')
:wikitext(
'[[File:Icon Item First.png|x25px|link=|alt=First]]'
)
end
end


Line 337: Line 441:
:addClass('card-modifier')
:addClass('card-modifier')
:addClass('card-modifier-up')
:addClass('card-modifier-up')
:wikitext('[[File:Icon Item UP.png|x25px|link=|alt=UP]]')
:wikitext(
'[[File:Icon Item UP.png|x25px|link=|alt=UP]]'
)
end
end


-- Label/text below card image
-- Label below the image
if ne(a.label) then
if ne(a.label) then
node_container:tag('span')
node_container:tag('span')
Line 347: Line 453:
end
end


-- Caption below card
-- Caption
if a.show_caption and ne(a.caption) then
-- 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')
local node_caption = node_container:tag('span')
:addClass('card-caption')
:addClass('card-caption')
:addClass('card-split-caption')


if a.nolink or lib.isEmpty(a.final_link) then
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)
node_caption:wikitext(a.caption)
else
else
node_caption:wikitext('[[', a.final_link, '|', a.caption, ']]')
node_caption:wikitext(
'[[' .. a.final_link .. '|' .. a.caption .. ']]'
)
end
end


Line 366: Line 493:
function p.templateData(frame)
function p.templateData(frame)
return TemplateData.templateData(CARD_ARGS, {
return TemplateData.templateData(CARD_ARGS, {
description = 'Creates an item-style card with image, quality, label, caption, modifiers, and optional data-driven icons.',
description = 'Creates an item-style card with image, quality, label, split images, modifiers, and optional data-driven icons.',
format = 'inline'
format = 'inline'
}, frame)
}, frame)