跳转到内容

Module:Fa:修订间差异

勤求古训,博采众方
创建页面,内容为“local p = {} --===== 配置区 ===== -- -- FontAwesome 版本和类名映射 local FA_VERSIONS = { [4] = { solid = "fa", regular = "fa", brands = "fa" }, [5] = { solid = "fas", regular = "far", brands = "fab" }, [6] = { solid = "fas", regular = "far", brands = "fab" }, [7] = { solid = "fa-solid", regular = "fa-regular", brands = "fa-brands" } } -- 样式缩写映射 local STYLE_MAP = { s = "solid", solid = "solid", r = "regular"…”
 
(没有差异)

2025年10月31日 (五) 00:11的最新版本

此模块的文档可以在Module:Fa/doc创建

local p = {}

--[[ 
===== 配置区 =====
--]]

-- FontAwesome 版本和类名映射
local FA_VERSIONS = {
    [4] = { solid = "fa", regular = "fa", brands = "fa" },
    [5] = { solid = "fas", regular = "far", brands = "fab" },
    [6] = { solid = "fas", regular = "far", brands = "fab" },
    [7] = { solid = "fa-solid", regular = "fa-regular", brands = "fa-brands" }
}

-- 样式缩写映射
local STYLE_MAP = {
    s = "solid", solid = "solid",
    r = "regular", regular = "regular",
    b = "brands", brands = "brands",
    l = "light", light = "light",
    d = "duotone", duotone = "duotone"
}

-- 图标别名系统
local ICON_ALIASES = {
    cog = "gear",
    refresh = "sync",
    trash = "trash-alt",
    envelope = "envelope-o"
}

-- 默认无障碍标签
local DEFAULT_TITLES = {
    question = "Help",
    gear = "Settings",
    rocket = "Rocket",
    home = "Home",
    search = "Search",
    user = "User"
}

-- 安全规则配置
local SECURITY = {
    max_size = "5em",
    safe_colors = {
        "red", "blue", "green", "black", "white",
        "#333", "#666", "#999", "#ccc", 
        "rgb(255,255,255)", "rgb(0,0,0)"
    },
    safe_icons = {
        "question", "gear", "rocket", "home",
        "search", "user", "envelope", "bell"
    }
}

--[[ 
===== 工具函数 ===== 
--]]

local function sanitize(text)
    return text and tostring(text):gsub("[<>%c]", "") or nil
end

local function validate_color(color)
    if not color then return nil end
    
    -- HEX 颜色 (#fff or #ffffff)
    if color:match("^#[0-9a-fA-F]{3,6}$") then
        return color:lower()
    end
    
    -- RGB 颜色
    if color:match("^rgb%(%d+%s*,%s*%d+%s*,%s*%d+%s*%)$") then
        return color:gsub("%s+", "")
    end
    
    -- 颜色名称白名单
    local safe_colors = {
        red = true, blue = true, green = true,
        black = true, white = true
    }
    return safe_colors[color:lower()] and color:lower() or nil
end

local function validate_size(size, strict_mode)
    if not size then return nil end
    
    -- 纯数字自动追加em单位
    if size:match("^%d+%.?%d*$") then
        size = size .. "em"
    end
    
    -- 带单位验证
    local num, unit = size:match("^(%d+%.?%d*)(em|rem|px|%%)$")
    if not num then return nil end
    
    num = tonumber(num)
    if strict_mode then
        if unit == "%" then return math.min(num, 100) .. unit end
        if unit == "px" then return math.min(num, 32) .. unit end
        return math.min(num, 5) .. unit
    end
    return num .. unit
end

local function validate_icon(icon, strict_mode)
    icon = sanitize(icon) or "question"
    icon = ICON_ALIASES[icon] or icon
    
    if strict_mode then
        for _, v in ipairs(SECURITY.safe_icons) do
            if v == icon then return icon end
        end
        return "question"
    end
    return icon:match("^[%w-]+$") and icon or "question"
end

--[[ 
===== 主函数 ===== 
--]]

function p.main(frame)
    if not frame or not frame.args then
        return '<span class="error">无效的模块调用</span>'
    end

    local args = frame.args
    local parent_args = frame:getParent().args
    
    -- 参数合并与处理
    local config = {
        icon = validate_icon(args.icon or parent_args.icon, args.mode == "strict"),
        version = tonumber(args.version or parent_args.version or 7),
        style = STYLE_MAP[args.style or parent_args.style or "s"] or "solid",
        size = validate_size(args.size or parent_args.size, args.mode == "strict"),
        color = validate_color(args.color or parent_args.color),
        spin = args.spin or parent_args.spin,
        title = sanitize(args.title or parent_args.title),
        id = sanitize(args.id or parent_args.id),
        class = sanitize(args.class or parent_args.class),
        mode = args.mode or parent_args.mode or "enhanced"
    }

    -- 版本回退
    config.version = FA_VERSIONS[config.version] and config.version or 7
    
    -- 默认标题
    config.title = config.title or DEFAULT_TITLES[config.icon]

    -- 严格模式颜色检查
    if config.mode == "strict" and config.color then
        local safe = false
        for _, v in ipairs(SECURITY.safe_colors) do
            if v == config.color then safe = true; break end
        end
        if not safe then config.color = nil end
    end

    -- 构建CSS类
    local classes = {
        FA_VERSIONS[config.version][config.style],
        "fa-" .. config.icon
    }
    if config.spin and config.spin ~= "false" then
        table.insert(classes, "fa-spin")
    end
    if config.class then
        for cls in config.class:gmatch("[%w-]+") do
            table.insert(classes, cls)
        end
    end

    -- 构建内联样式
    local styles = {}
    if config.size then table.insert(styles, "font-size:" .. config.size) end
    if config.color then table.insert(styles, "color:" .. config.color) end

    -- 生成HTML
    local html = mw.html.create("span")
        :attr("role", "img")
        :css("display", "inline-flex")
        :css("align-items", "center")
        :tag("i")
            :addClass(table.concat(classes, " "))
            :attr("aria-hidden", "true")
            :attr("title", config.title)
            :attr("id", config.id)
            :cssText(table.concat(styles, ";"))

    if config.title then
        html:done():tag("span")
            :addClass("screen-reader-only")
            :wikitext(config.title)
    end

    return tostring(html)
end

return p