模块:Background
来自Blockland Wiki
更多操作
此模块的文档可以在模块:Background/doc创建
local p = {}
local function trim(value)
return mw.text.trim(tostring(value or ""))
end
local function getOpacity(value, default)
local number = tonumber(trim(value))
if not number or number ~= number then
return default
end
number = math.max(0, math.min(1, number))
return tostring(number)
end
local positionNames = {
center = true,
top = true,
bottom = true,
left = true,
right = true
}
local validPositions = {
center = true,
["center center"] = true,
["center top"] = true,
["center bottom"] = true,
["left center"] = true,
["right center"] = true,
["left top"] = true,
["right top"] = true,
["left bottom"] = true,
["right bottom"] = true,
top = true,
bottom = true,
left = true,
right = true
}
local function validPositionToken(value)
if positionNames[value] then
return true
end
if value == "0" then
return true
end
return value:match("^%-?%d+%.?%d*%%$") ~= nil
or value:match("^%-?%d+%.?%d*px$") ~= nil
end
local function getPosition(value)
value = trim(value)
if validPositions[value] then
return value
end
local x, y = value:match("^(%S+)%s+(%S+)$")
if x and y
and validPositionToken(x)
and validPositionToken(y) then
return x .. " " .. y
end
return "center center"
end
local colorNames = {
white = true,
black = true,
transparent = true,
red = true,
blue = true,
green = true,
yellow = true,
gray = true,
grey = true,
navy = true
}
local function getColor(value)
value = trim(value)
if value:match("^#%x%x%x$")
or value:match("^#%x%x%x%x%x%x$") then
return value
end
local lower = value:lower()
if colorNames[lower] then
return lower
end
return ""
end
-- 支持直接 URL、普通文件名,以及被展开成 HTML 的文件链接。
local function getImageSource(frame, value)
value = trim(value)
if value == "" then
return ""
end
-- 如果模板参数已被展开成图片 HTML,提取其 src。
local embedded =
value:match('<img[^>]-src="([^"]+)"')
or value:match("<img[^>]-src='([^']+)'")
if embedded then
return embedded:gsub("&", "&")
end
-- 去除尚未展开的 Wiki 文件链接标记及显示参数。
value = value:gsub("^%[%[", "")
value = value:gsub("%]%]$", "")
value = value:match("^([^|]+)") or value
value = trim(value)
-- 外部图片地址。
if value:match("^https?://%S+$")
or value:match("^//%S+$") then
return value
end
-- 已经是站内图片路径。
if value:match("^/images/")
or value:match("^/wiki/Special:FilePath/") then
return value
end
-- 转换成纯文件名,不要把文件链接语法交给 filepath。
value = value:gsub("^[Ff][Ii][Ll][Ee]:", "")
value = value:gsub("^[Ii][Mm][Aa][Gg][Ee]:", "")
value = value:gsub("^文件:", "")
value = value:gsub("^图像:", "")
value = trim(value)
local ok, result = pcall(function()
return frame:callParserFunction("filepath", value)
end)
if ok and result then
result = trim(result)
if result ~= ""
and not result:find("<", 1, true)
and not result:find(">", 1, true) then
return result
end
end
return ""
end
function p.main(frame)
local parent = frame:getParent()
local args = parent and parent.args or frame.args
local image = args["图片"]
or args["url"]
or args[1]
or ""
local src = getImageSource(frame, image)
local imageOpacity = getOpacity(
args["透明度"] or args["opacity"],
1
)
local imagePosition = getPosition(
args["位置"] or args["position"] or "center"
)
local baseColor = getColor(
args["背景色"] or args["颜色"] or args["color"]
)
local shadeColor = getColor(
args["遮罩颜色"] or args["shadeColor"]
)
local shadeOpacity = getOpacity(
args["遮罩透明度"] or args["shade"],
0
)
if src == "" and baseColor == "" then
return ""
end
-- 整个背景位于较低层级,不应截获鼠标事件。
local rootStyle =
"position:fixed;" ..
"top:0;" ..
"left:0;" ..
"width:100%;" ..
"height:100%;" ..
"z-index:-1;" ..
"overflow:hidden;" ..
"pointer-events:none;"
if baseColor ~= "" then
rootStyle = rootStyle ..
"background-color:" .. baseColor .. ";"
end
local root = mw.html.create("div")
:addClass("bl-page-bg-layer")
:attr("aria-hidden", "true")
:cssText(rootStyle)
-- 第一层:背景图片。
if src ~= "" then
local img = mw.html.create("img")
:addClass("bl-page-bg-image")
:attr("src", src)
:attr("alt", "")
:cssText(
"position:absolute;" ..
"top:0;" ..
"left:0;" ..
"width:100%;" ..
"height:100%;" ..
"max-width:none;" ..
"object-fit:cover;" ..
"object-position:" .. imagePosition .. ";" ..
"opacity:" .. imageOpacity .. ";" ..
"pointer-events:none;"
)
-- 关键:插入 HTML 节点,不再使用 wikitext(tostring(img))。
root:node(img)
end
-- 第二层:颜色遮罩,用来降低背景的视觉干扰。
if shadeColor ~= ""
and tonumber(shadeOpacity) > 0 then
local shade = mw.html.create("div")
:addClass("bl-page-bg-shade")
:cssText(
"position:absolute;" ..
"top:0;" ..
"left:0;" ..
"width:100%;" ..
"height:100%;" ..
"background-color:" .. shadeColor .. ";" ..
"opacity:" .. shadeOpacity .. ";" ..
"pointer-events:none;"
)
root:node(shade)
end
return tostring(root)
end
return p