Module:Card: Difference between revisions
No edit summary |
No edit summary |
||
| (29 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 ne = lib.isNotEmpty | local ne = lib.isNotEmpty | ||
local | 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 | ||
{' | |||
{' | 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, { | ||
wrapper = { 'Template:Card' }, | wrapper = {'Template:Card'}, | ||
parentOnly = false | parentOnly = false | ||
}) | }) | ||
return p._main(args) | return p._main(args) | ||
end | end | ||
function | local function getDataByName(dataType, dataTable, name) | ||
local | local data = dataTable[name] | ||
if data then | |||
return data | |||
end | |||
local normalizedType = tostring(dataType or ''):lower() | |||
local | 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 | ||
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 | end | ||
- | return img_type, img_data | ||
if | 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 | firstItemOnly = 1 | ||
}) | }) | ||
end | 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". | |||
if lib.isEmpty( | 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 | end | ||
if lib.isEmpty(out.suffix) then | |||
out.suffix = ' Icon' | |||
end | end | ||
-- | -- Data-driven defaults | ||
if out.data then | |||
if | if out.data.name then | ||
label = data | 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 | 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 | ||
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 | end | ||
if | if out.label == '0' then | ||
out.label = nil | |||
end | end | ||
-- | -- Type-specific behavior | ||
if | local lcType = tostring(out.type or ''):lower() | ||
if | |||
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 | end | ||
if | |||
if tonumber(out.image_size) then | |||
out.image_size = tonumber(out.image_size) + 2 | |||
end | 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 | ||
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 | |||
if | |||
end | end | ||
end | end | ||
if | -- 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 | 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. | function p._main(args) | ||
local | local a = p._processArgs(args) | ||
local | local isSplit = ne(a.split) | ||
-- Outer container | |||
-- | local node_container = mw.html.create('div') | ||
if | :addClass('card-container') | ||
local | |||
if isSplit then | |||
node_container:addClass('card-split-card') | |||
end | |||
if a.mini then | |||
node_container:addClass('mini-card') | |||
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 | |||
imageContainer:tag('span') | |||
:addClass('card-split-half') | |||
:addClass('card-split-half-b') | |||
:wikitext(makeSplitIcon(a.split, a.mini)) | |||
else | |||
imageContainer:wikitext(a.image_wikitext) | |||
end | |||
-- Notice label | |||
if not a.mini and ne(a.notice) then | |||
node_card:tag('span') | |||
:addClass('card-notice-label') | |||
:wikitext(a.notice) | |||
end | |||
-- First modifier | |||
if a.first then | |||
node_card:tag('span') | |||
:addClass('card-modifier') | |||
:addClass('card-modifier-first') | |||
:wikitext( | |||
'[[File:Icon Item First.png|x25px|link=|alt=First]]' | |||
) | |||
end | |||
-- UP modifier | |||
if a.up then | |||
node_card:tag('span') | |||
:addClass('card-modifier') | |||
:addClass('card-modifier-up') | |||
:wikitext( | |||
'[[File:Icon Item UP.png|x25px|link=|alt=UP]]' | |||
) | |||
end | |||
-- Label below the image | |||
if ne(a.label) then | |||
node_container:tag('span') | |||
:addClass('card-label') | |||
:wikitext(a.label) | |||
end | |||
-- Caption | |||
-- 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 | end | ||
setCaptionWidth(node_caption, a.caption_width) | |||
end | end | ||
return | 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 | ||