Mudanças entre as edições de "Módulo:Droflax"
Ir para navegação
Ir para pesquisar
| Linha 11: | Linha 11: | ||
end | end | ||
-- Construir estructura de datos | -- Construir estructura de datos optimizada | ||
local data = { | local data = { | ||
nome = args.nome, | nome = args.nome, | ||
tier = args.tier or '', | tier = args.tier or '', | ||
classe = args.classe or '', | classe = args.classe or '', | ||
image = args.image or '', | image = args.image or '', | ||
habilidades = {}, | habilidades = {}, | ||
skins = {} | skins = {} | ||
} | } | ||
-- Procesar habilidades (1-15) | -- Procesar habilidades (1-15) con validación | ||
for i = 1, 15 do | for i = 1, 15 do | ||
if args['hab'..i..'-nome'] then | if args['hab'..i..'-nome'] and args['hab'..i..'-nome'] ~= '' then | ||
table.insert(data.habilidades, { | table.insert(data.habilidades, { | ||
nome = args['hab'..i..'-nome'], | nome = args['hab'..i..'-nome'], | ||
icon = args['hab'..i..'-icon'], | icon = args['hab'..i..'-icon'] or '', | ||
level = tonumber(args['hab'..i..'-level']) or 0, | level = tonumber(args['hab'..i..'-level']) or 0, | ||
desc = args['hab'..i..'-desc'] or '', | desc = args['hab'..i..'-desc'] or '', | ||
atr = args['hab'..i..'-atr'] or '', | atr = args['hab'..i..'-atr'] or '', | ||
video = args['hab'..i..'-video'] or '' | video = args['hab'..i..'-video'] or '' | ||
}) | }) | ||
end | end | ||
end | end | ||
-- Procesar skins (1-5) | -- Procesar skins (1-5) con validación | ||
for i = 1, 5 do | for i = 1, 5 do | ||
if args['skin'..i..'-image'] then | if args['skin'..i..'-image'] and args['skin'..i..'-image'] ~= '' then | ||
table.insert(data.skins, { | table.insert(data.skins, { | ||
image = args['skin'..i..'-image'], | image = args['skin'..i..'-image'], | ||
tooltip = (args['skin'..i..'-tooltip'] or ''):gsub('\n', '<br>') | tooltip = (args['skin'..i..'-tooltip'] or ''):gsub('\n', '<br>') | ||
}) | }) | ||
| Linha 45: | Linha 45: | ||
end | end | ||
-- Construir HTML | -- Construir HTML optimizado | ||
local html = mwHtml.create('div') | local html = mwHtml.create('div') | ||
:addClass('personaje-box') | :addClass('personaje-box') | ||
:addClass('tier-' .. (data.tier:lower() or '')) | :addClass('tier-' .. (data.tier:lower() or '')) | ||
:attr('data-loaded', 'false') -- Para que JS detecte cuando puede actuar | |||
-- Cabecera | -- Cabecera optimizada | ||
local header = html:tag('div') | local header = html:tag('div') | ||
:addClass('personaje-header') | :addClass('personaje-header') | ||
| Linha 58: | Linha 59: | ||
:wikitext(string.format([[ | :wikitext(string.format([[ | ||
<div class="personaje-nome-box"> | <div class="personaje-nome-box"> | ||
<img src="/images/6/63/Franky_ts_medal.png" class="topbar-icon" loading="lazy"> | <img src="/images/6/63/Franky_ts_medal.png" class="topbar-icon" loading="lazy" width="40" height="40"> | ||
<div class="personaje-nome-category"> | <div class="personaje-nome-category"> | ||
<div class="nome">%s</div> | <div class="nome">%s</div> | ||
| Linha 67: | Linha 68: | ||
]], data.nome, data.classe, data.nome, data.tier)) | ]], data.nome, data.classe, data.nome, data.tier)) | ||
-- Tabs | -- Tabs con accesibilidad mejorada | ||
header:tag('div') | header:tag('div') | ||
:addClass('personaje-tabs') | :addClass('personaje-tabs') | ||
:attr('role', 'tablist') | |||
:wikitext([[ | :wikitext([[ | ||
<button class="tab-btn" data-tab="arma">Arma</button> | <button class="tab-btn" data-tab="arma" role="tab" aria-selected="false">Arma</button> | ||
<button class="tab-btn active" data-tab="habilidades">Habilidades</button> | <button class="tab-btn active" data-tab="habilidades" role="tab" aria-selected="true">Habilidades</button> | ||
<button class="tab-btn" data-tab="skins">Skins</button> | <button class="tab-btn" data-tab="skins" role="tab" aria-selected="false">Skins</button> | ||
]]) | ]]) | ||
-- | -- Imagen principal con optimización | ||
if data.image ~= '' then | if data.image ~= '' then | ||
html:tag('link') | html:tag('link') | ||
| Linha 82: | Linha 84: | ||
:attr('href', data.image) | :attr('href', data.image) | ||
:attr('as', 'image') | :attr('as', 'image') | ||
:attr('fetchpriority', 'high') | |||
:done() | :done() | ||
html:tag('img') | |||
:addClass('art-personaje') | |||
:attr('src', data.image) | |||
:attr('alt', data.nome) | |||
:attr('loading', 'eager') | |||
:attr('width', '300') | |||
:attr('height', '300') | |||
:attr('decoding', 'async') | |||
end | end | ||
-- Precarga de recursos importantes con priorización | |||
-- Precarga de recursos importantes | |||
if #data.habilidades > 0 then | if #data.habilidades > 0 then | ||
-- Precargar primeros 3 iconos de habilidades | -- Precargar primeros 3 iconos de habilidades | ||
| Linha 100: | Linha 106: | ||
:attr('href', data.habilidades[i].icon) | :attr('href', data.habilidades[i].icon) | ||
:attr('as', 'image') | :attr('as', 'image') | ||
:attr('fetchpriority', 'low') | |||
:done() | :done() | ||
end | end | ||
end | end | ||
end | end | ||
-- Contenedor de habilidades | -- Contenedor de habilidades optimizado | ||
local habilidadesContainer = html:tag('div') | local habilidadesContainer = html:tag('div') | ||
:addClass('tab-content') | :addClass('tab-content') | ||
:addClass('active') | :addClass('active') | ||
:attr('id', 'habilidades') | :attr('id', 'habilidades') | ||
:attr('role', 'tabpanel') | |||
local cuadrosContainer = habilidadesContainer:tag('div') | local cuadrosContainer = habilidadesContainer:tag('div') | ||
| Linha 124: | Linha 123: | ||
for i, hab in ipairs(data.habilidades) do | for i, hab in ipairs(data.habilidades) do | ||
cuadrosContainer:tag('div') | local cuadro = cuadrosContainer:tag('div') | ||
:addClass('cuadro') | :addClass('cuadro') | ||
:attr('data-index', i) | :attr('data-index', i) | ||
:attr('title', hab.nome) | :attr('title', hab.nome) | ||
: | :attr('aria-label', hab.nome) | ||
' | |||
if hab.icon ~= '' then | |||
) | cuadro:tag('img') | ||
:attr('src', hab.icon) | |||
:attr('alt', hab.nome) | |||
:attr('loading', 'lazy') | |||
:attr('width', '40') | |||
:attr('height', '40') | |||
:attr('decoding', 'async') | |||
else | |||
cuadro:wikitext('<div class="icon-placeholder"></div>') | |||
end | |||
end | end | ||
| Linha 144: | Linha 152: | ||
]]) | ]]) | ||
-- Contenedor de skins | -- Contenedor de skins optimizado | ||
local skinsContainer = html:tag('div') | local skinsContainer = html:tag('div') | ||
:addClass('tab-content') | :addClass('tab-content') | ||
:attr('id', 'skins') | :attr('id', 'skins') | ||
:attr('role', 'tabpanel') | |||
if #data.skins > 0 then | if #data.skins > 0 then | ||
| Linha 154: | Linha 163: | ||
<span class="card-skins-title">SKINS & SPOTLIGHTS</span> | <span class="card-skins-title">SKINS & SPOTLIGHTS</span> | ||
<div class="skins-carousel-wrapper"> | <div class="skins-carousel-wrapper"> | ||
<button class="skins-arrow left">«</button> | <button class="skins-arrow left" aria-label="Anterior skin">«</button> | ||
<div class="skins-carousel"> | <div class="skins-carousel"> | ||
]]) | ]]) | ||
| Linha 160: | Linha 169: | ||
for _, skin in ipairs(data.skins) do | for _, skin in ipairs(data.skins) do | ||
skinsContainer:wikitext(string.format([[ | skinsContainer:wikitext(string.format([[ | ||
<div class="skin-card" title="%s"> | <div class="skin-card" title="%s" aria-label="%s"> | ||
<img class="skins--imageBanner" src="/images/default-skin-banner.jpg" loading="lazy"> | <img class="skins--imageBanner" src="/images/default-skin-banner.jpg" loading="lazy" width="200" height="80"> | ||
<img class="skins--imageSkin" src="%s" loading="lazy"> | <img class="skins--imageSkin" src="%s" loading="lazy" width="150" height="150"> | ||
</div> | </div> | ||
]], skin.tooltip, skin.image)) | ]], skin.tooltip, skin.tooltip, skin.image)) | ||
end | end | ||
skinsContainer:wikitext([[ | skinsContainer:wikitext([[ | ||
</div> | </div> | ||
<button class="skins-arrow right">»</button> | <button class="skins-arrow right" aria-label="Siguiente skin">»</button> | ||
</div> | </div> | ||
</div> | </div> | ||
| Linha 175: | Linha 184: | ||
end | end | ||
-- Incluir datos para JS | -- Incluir datos para JS de forma segura | ||
html:tag('script') | html:tag('script') | ||
:attr('type', 'application/json') | :attr('type', 'application/ld+json') | ||
:attr('id', 'personaje-data-json') | :attr('id', 'personaje-data-json') | ||
:wikitext(mw.text.jsonEncode(data)) | :wikitext(mw.text.jsonEncode(data)) | ||
| Linha 183: | Linha 192: | ||
return tostring(html) | return tostring(html) | ||
end | end | ||
return p | return p | ||
Edição das 23h12min de 19 de julho de 2025
A documentação para este módulo pode ser criada em Módulo:Droflax/doc
local p = {}
function p.render(frame)
local args = frame:getParent().args
local mwHtml = require('mw.html')
local util = require('libraryUtil')
-- Validación básica
if not args.nome or args.nome == '' then
return '<div class="error">Falta el nombre del personaje</div>'
end
-- Construir estructura de datos optimizada
local data = {
nome = args.nome,
tier = args.tier or '',
classe = args.classe or '',
image = args.image or '',
habilidades = {},
skins = {}
}
-- Procesar habilidades (1-15) con validación
for i = 1, 15 do
if args['hab'..i..'-nome'] and args['hab'..i..'-nome'] ~= '' then
table.insert(data.habilidades, {
nome = args['hab'..i..'-nome'],
icon = args['hab'..i..'-icon'] or '',
level = tonumber(args['hab'..i..'-level']) or 0,
desc = args['hab'..i..'-desc'] or '',
atr = args['hab'..i..'-atr'] or '',
video = args['hab'..i..'-video'] or ''
})
end
end
-- Procesar skins (1-5) con validación
for i = 1, 5 do
if args['skin'..i..'-image'] and args['skin'..i..'-image'] ~= '' then
table.insert(data.skins, {
image = args['skin'..i..'-image'],
tooltip = (args['skin'..i..'-tooltip'] or ''):gsub('\n', '<br>')
})
end
end
-- Construir HTML optimizado
local html = mwHtml.create('div')
:addClass('personaje-box')
:addClass('tier-' .. (data.tier:lower() or ''))
:attr('data-loaded', 'false') -- Para que JS detecte cuando puede actuar
-- Cabecera optimizada
local header = html:tag('div')
:addClass('personaje-header')
header:tag('div')
:addClass('personaje-topbar')
:wikitext(string.format([[
<div class="personaje-nome-box">
<img src="/images/6/63/Franky_ts_medal.png" class="topbar-icon" loading="lazy" width="40" height="40">
<div class="personaje-nome-category">
<div class="nome">%s</div>
<div class="classes">%s</div>
</div>
</div>
<div class="topbar-description">%s é um personagem do tier %s.</div>
]], data.nome, data.classe, data.nome, data.tier))
-- Tabs con accesibilidad mejorada
header:tag('div')
:addClass('personaje-tabs')
:attr('role', 'tablist')
:wikitext([[
<button class="tab-btn" data-tab="arma" role="tab" aria-selected="false">Arma</button>
<button class="tab-btn active" data-tab="habilidades" role="tab" aria-selected="true">Habilidades</button>
<button class="tab-btn" data-tab="skins" role="tab" aria-selected="false">Skins</button>
]])
-- Imagen principal con optimización
if data.image ~= '' then
html:tag('link')
:attr('rel', 'preload')
:attr('href', data.image)
:attr('as', 'image')
:attr('fetchpriority', 'high')
:done()
html:tag('img')
:addClass('art-personaje')
:attr('src', data.image)
:attr('alt', data.nome)
:attr('loading', 'eager')
:attr('width', '300')
:attr('height', '300')
:attr('decoding', 'async')
end
-- Precarga de recursos importantes con priorización
if #data.habilidades > 0 then
-- Precargar primeros 3 iconos de habilidades
for i = 1, math.min(3, #data.habilidades) do
if data.habilidades[i].icon ~= '' then
html:tag('link')
:attr('rel', 'preload')
:attr('href', data.habilidades[i].icon)
:attr('as', 'image')
:attr('fetchpriority', 'low')
:done()
end
end
end
-- Contenedor de habilidades optimizado
local habilidadesContainer = html:tag('div')
:addClass('tab-content')
:addClass('active')
:attr('id', 'habilidades')
:attr('role', 'tabpanel')
local cuadrosContainer = habilidadesContainer:tag('div')
:addClass('cuadros-container')
for i, hab in ipairs(data.habilidades) do
local cuadro = cuadrosContainer:tag('div')
:addClass('cuadro')
:attr('data-index', i)
:attr('title', hab.nome)
:attr('aria-label', hab.nome)
if hab.icon ~= '' then
cuadro:tag('img')
:attr('src', hab.icon)
:attr('alt', hab.nome)
:attr('loading', 'lazy')
:attr('width', '40')
:attr('height', '40')
:attr('decoding', 'async')
else
cuadro:wikitext('<div class="icon-placeholder"></div>')
end
end
-- Contenedor de detalles de habilidades
habilidadesContainer:tag('div')
:addClass('habilidades-container')
:wikitext([[
<div class="habilidades-details">
<div class="descripcion-container"></div>
</div>
<div class="video-container"></div>
]])
-- Contenedor de skins optimizado
local skinsContainer = html:tag('div')
:addClass('tab-content')
:attr('id', 'skins')
:attr('role', 'tabpanel')
if #data.skins > 0 then
skinsContainer:wikitext([[
<div class="card-skins">
<span class="card-skins-title">SKINS & SPOTLIGHTS</span>
<div class="skins-carousel-wrapper">
<button class="skins-arrow left" aria-label="Anterior skin">«</button>
<div class="skins-carousel">
]])
for _, skin in ipairs(data.skins) do
skinsContainer:wikitext(string.format([[
<div class="skin-card" title="%s" aria-label="%s">
<img class="skins--imageBanner" src="/images/default-skin-banner.jpg" loading="lazy" width="200" height="80">
<img class="skins--imageSkin" src="%s" loading="lazy" width="150" height="150">
</div>
]], skin.tooltip, skin.tooltip, skin.image))
end
skinsContainer:wikitext([[
</div>
<button class="skins-arrow right" aria-label="Siguiente skin">»</button>
</div>
</div>
]])
end
-- Incluir datos para JS de forma segura
html:tag('script')
:attr('type', 'application/ld+json')
:attr('id', 'personaje-data-json')
:wikitext(mw.text.jsonEncode(data))
return tostring(html)
end
return p