local p = {}
local getArgs = require('Module:Arguments').getArgs
local Split = require('Module:Split2')
function p.main(frame)
local args = getArgs(frame, {
parentFirst = true,
})
return p._main(args)
end
function p._main(args)
local output = {}
local charaHTMLMap = {}
-- 参数解析和默认值设置
local image = args.image or ''
local charas = args.charas or ''
local start = tonumber(args.start) or 1
local size = tonumber(args.size) or 0
local width = tonumber(args.width) or 0
local height = tonumber(args.height) or 0
local fitWidth = tonumber(args.fitWidth) or 0
local fitHeight = tonumber(args.fitHeight) or 0
local offsetX = tonumber(args.offsetX) or 0
local offsetY = tonumber(args.offsetY) or 0
local scale = tonumber(args.scale) or 1
local targetSize = tonumber(args.targetSize) or width
local radius = args.radius or '0'
local blockStyle = args.blockStyle or 'margin:0 5px'
local imgContainerStyle = args.imgContainerStyle or ''
local class = args.class or ''
-- 计算缩放因子
local scale_factor = scale
if targetSize and width ~= 0 then
scale_factor = scale * (targetSize / width)
end
-- 计算缩放后的尺寸
local scaled_width = width * scale_factor
local scaled_height = height * scale_factor
local container_width = scaled_width + fitWidth
local container_height = scaled_height + fitHeight
-- 处理charas参数
if charas ~= '' then
local charaInfo = Split.split(charas, ',', false)
for i = 1, charaInfo.count do
local charaStr = charaInfo.parts[i]
local page, charaName
-- 解析页面名和显示名
if charaStr:find('=') then
page, charaName = charaStr:match('^%s*(.-)%s*=%s*(.-)%s*$')
else
page = charaStr
charaName = charaStr
end
-- 计算雪碧图位置
local index = start + i - 1
local x = (width + offsetX) * (index - 1) * scale_factor
local y = 0
if offsetY ~= 0 then
y = (height + offsetY) * (index - 1) * scale_factor
end
-- 生成HTML代码
local li_html = string.format(
'<li style="float:left; margin:0 5px; text-align:center; list-style:none; %s">%s[[%s|%s]]</li>',
blockStyle,
generateImageClip(image, container_width, container_height, x, y, scaled_width, scaled_height, radius, imgContainerStyle, class, page),
page,
charaName
)
-- 存储到映射表
charaHTMLMap[charaName] = li_html
-- 如果没有无名参数,直接添加到输出
if not hasUnnamedArgs(args) then
table.insert(output, li_html)
end
end
end
-- 处理无名参数(重新排序)
if hasUnnamedArgs(args) then
for i = 1, getMaxUnnamedArg(args) do
local value = args[tostring(i)]
if not value then break end
if value:find('@space,') or isImageFile(value) then
-- 处理单独图片
local parts = Split.split(value, ',', false)
local imageFile, page, displayName
if parts.count == 2 then
imageFile = parts.parts[1]
page = parts.parts[2]
displayName = parts.parts[2]
elseif parts.count >= 3 then
imageFile = parts.parts[1]
page = parts.parts[2]
displayName = parts.parts[3]
end
local li_html = generateSingleImage(page, displayName, imageFile, container_width, container_height, scaled_width, imgContainerStyle, class)
table.insert(output, li_html)
else
-- 使用之前存储的HTML
if charaHTMLMap[value] then
table.insert(output, charaHTMLMap[value])
end
end
end
end
-- 处理add参数 - 支持无限多个
local addKeys = {}
for key, value in pairs(args) do
if key:match('^add%d+$') then
local num = tonumber(key:match('%d+$'))
table.insert(addKeys, {key = key, num = num})
end
end
-- 按数字排序
table.sort(addKeys, function(a, b) return a.num < b.num end)
for _, item in ipairs(addKeys) do
local value = args[item.key]
if value:find('@space,') or isImageFile(value) then
local parts = Split.split(value, ',', false)
local imageFile, page, displayName
if parts.count == 2 then
imageFile = parts.parts[1]
page = parts.parts[2]
displayName = parts.parts[2]
elseif parts.count >= 3 then
imageFile = parts.parts[1]
page = parts.parts[2]
displayName = parts.parts[3]
end
local li_html = generateSingleImage(page, displayName, imageFile, container_width, container_height, scaled_width, imgContainerStyle, class)
table.insert(output, li_html)
end
end
return table.concat(output, '\n')
end
-- 辅助函数:检查是否有无名参数
function hasUnnamedArgs(args)
for k, v in pairs(args) do
if tonumber(k) then
return true
end
end
return false
end
-- 辅助函数:获取最大的无名参数索引
function getMaxUnnamedArg(args)
local max = 0
for k, v in pairs(args) do
local num = tonumber(k)
if num and num > max then
max = num
end
end
return max
end
-- 辅助函数:检查是否为图片文件
function isImageFile(filename)
local extensions = {'.jpg', '.jpeg', '.png', '.gif', '.svg', '.webp'}
for _, ext in ipairs(extensions) do
if filename:lower():find(ext .. ',') then
return true
end
end
return false
end
-- 生成雪碧图裁剪的HTML
function generateImageClip(image, container_width, container_height, x, y, scaled_width, scaled_height, radius, imgContainerStyle, class, linkPage)
local style = string.format(
'display:inline-block; width:%fpx; height:%fpx; overflow:hidden; position:relative; %s',
container_width, container_height, imgContainerStyle
)
local innerStyle = string.format(
'position:absolute; width:%fpx; height:%fpx; background:url(%s) no-repeat -%fpx -%fpx; border-radius:%s;',
scaled_width, scaled_height, image, x, y, radius
)
local html = string.format(
'%s<div style="%s"><div style="%s"></div></div>%s<br />',
class ~= '' and string.format('<div class="%s">', class) or '',
style,
innerStyle,
class ~= '' and '</div>' or ''
)
return html
end
-- 生成单独图片的HTML
function generateSingleImage(page, displayName, imageFile, container_width, container_height, scaled_width, imgContainerStyle, class)
local imageHtml
if imageFile == '@space' then
imageHtml = string.format(
'<span style="display:inline-block; width:%fpx; height:%fpx; %s"></span>',
container_width, container_height, imgContainerStyle
)
else
imageHtml = string.format(
'<span style="display:inline-block; width:%fpx; height:%fpx; %s">[[File:%s|width=%fpx|style=float:left;]]</span>',
container_width, container_height, imgContainerStyle, imageFile, scaled_width
)
end
return string.format(
'<li style="float:left; margin:0 5px; text-align:center; list-style:none;">%s%s<br />[[%s|%s]]</li>',
class ~= '' and string.format('<span class="%s">', class) or '',
imageHtml,
page,
displayName
)
end
return p