模块:Lyrics/multi

来自维阿百科
跳转至: 导航搜索

此模块的文档可以在模块:Lyrics/multi/doc创建

local p = {}

local getArgs = require("Module:Arguments").getArgs
local lang = require("Module:Lang")
local errmsg = require("Module:Error")
local lrcmod = require("Module:Lyrics/colors")

local getCharaBlock = require("Module:Lyrics/colors/sub")._charaBlock

local showErrorMessage = function(msg, args)
    if args.errMsg ~= "off" then
        return errmsg.error{ message = msg }
    end
end

local ce_cache = {}
local apply_ce = function(text)
	text = mw.ustring.gsub(text, '%$([%d%$%[@])', function(s)
		if not ce_cache[s] then ce_cache[s] = mw.getCurrentFrame():expandTemplate{ title = 'ce', args = {s} } end
		return ce_cache[s]
	end)
	text = mw.ustring.gsub(text, '@%[([^%[]-)%]', function(match) return '@' .. (customArgs.map_aliases[match] and customArgs.map_aliases[match] or '['..match..']') end)
	return text
end

function p._lyrics(args)
    ------------------------ 处理参数 ------------------------
    local colorsMode = args.colorsMode == "on" -- 是否开启彩色显示开关。
    
    local colors, map_aliases, charas = lrcmod.parseArgs(args.colors or '', args.charas or '', args.charaBlock)
    
    local versions = {}
    for k, v in pairs(args) do
        if type(k) == "number" then
            local def = mw.text.trim(mw.ustring.gsub(v or "", "\n", "")) -- 删除名称定义语句中的所有换行及首尾空白字符。
            local key, aliases = mw.ustring.match(def, "^([^%[]*)%[([^%]]*)%]$") -- 匹配名称和缩写列表。
            if key == nil then
                if mw.ustring.find(def, "[%[%]]") then -- 有意定义缩写列表,因此为格式错误。
                    if args.errMsg ~= "off" then
                        return errmsg.error{ message = mw.ustring.format("格式错误:第%d个名称定义语句“%s”中括号“[”和“]”不配对。", k, v) }
                    end
                else
                    key = def -- 无意定义缩写列表,将整个字符串视为名称。
                end
            end
            key = mw.text.trim(key) -- 去除首尾空白字符。
            if key == "" then
                if args.errMsg ~= "off" then
                    return errmsg.error{ message = mw.ustring.format("格式错误:在第%d个名称定义语句“%s”中未找到名称或者全部为空白字符。", k, v) }
                end
            else
                -- 获取所有缩写名称
                local inter = mw.text.gsplit(aliases or "", ",")
                aliases = {}
                for alias in inter do
                    alias = mw.text.trim(alias)
                    if alias ~= "" and aliases[alias] == nil then
                        table.insert(aliases, alias)
                        aliases[alias] = true
                    end
                end
                
                -- 获取名称及缩写对应参数值的通用函数。
                local getParam = function(postfix)
                    local temp = args[key..postfix] -- 以名称优先。
                    if mw.text.trim(temp or "") == "" then -- 名称对应参数不存在,则按顺序检查缩写对应参数。
                        temp = nil
                        for _, alias in ipairs(aliases) do
                            if mw.text.trim(args[alias..postfix] or "") ~= "" then -- 这个缩写对应的参数符合条件。
                                if temp ~= nil then -- 已有符合条件的对应参数。
                                    if args.errMsg ~= "off" then
                                        return false, errmsg.error{ message = mw.ustring.format("检测到重复的参数“%s”和“%s”,它们使用的名称缩写“%s”和“%s”都表示“%s”。", temp..postfix, alias..postfix, temp, alias, key) }
                                    end
                                    --temp = alias -- 顺序后的覆盖顺序前的。
                                end
                                temp = alias
                            end
                        end
                        if temp ~= nil then
                            temp = args[temp..postfix]
                        end
                    end
                    return true, temp
                end
                
                local success, result
                -- 获取语言代码。
                success, result = getParam("lang")
                if not success then
                    return result
                end
                local lang = result
                
                -- 获取自定义样式。
                success, result = getParam("style")
                if not success then
                    return result
                end
                local style = result
                
                -- 获取歌词的所有行。
                local lines = mw.text.split(apply_ce(args[key] or ""):match("^(.-)%s*$"), "\n")
                if colorsMode then -- 开启颜色模式。
                    -- 检查该列是否需要颜色处理。
                    success, result = getParam("Colors")
                    if not success then
                        return result
                    end
                    -- 默认第一列需要颜色处理。
                    if #versions == 0 then
                        result = result or "on"
                        lines = lrcmod.parse(colors, charas, args.chorusName or '', lines)
                    elseif result == "on" then
                        -- 解析颜色歌词。
                        lines = lrcmod.parse(colors, charas, args.chorusName or '', lines)
                    end
                end
                
                -- 将每一个翻译版本创建成项。
                if args[key] ~= nil then
                    table.insert(versions, key)
                    local entry = {
                        lines = lines,
                        lang = lang,
                        style = style
                    }
                    if #versions == 1 then entry.lang = entry.lang or "ja" -- 默认第一列时日文。
                    else entry.lang = entry.lang or "zh" -- 默认第二列时中文。
                    end
                    
                    versions[key] = entry
                end
            end
        end
    end
    
    ------------------------ 核心代码 ------------------------
    local html = mw.html.create("div")
        :addClass("Lyrics")
        :css("width", args.width)
        :cssText(args.containerstyle)
    
    -- 检查任何一列歌词是否包含ruby。
    if mw.text.trim(args.hasRuby or "") ~= "" then
        html:addClass("Lyrics-has-ruby")
    else
        local hasRuby = false
        for i = 1, #versions do
            if args[versions[i]]:find("<ruby") then
                hasRuby = true
                break
            end
        end
        
        if hasRuby then
            html:addClass("Lyrics-has-ruby")
        else
            html:addClass("Lyrics-no-ruby")
        end
    end

    -- 创建charaBlock。
    if args.charaBlock == "on" then
        html:tag("p"):node(getCharaBlock{
            colors = args.colors,
            charas = args.charas,
            groupName = args.groupName,
            groupColor = versions[versions[1]].style -- 默认为第1列的样式
        })
    end

    local len = 0 -- 行数的最大值
    for i = 1, #versions do
        len = math.max(len, #(versions[versions[i]].lines))
    end

    for line = 1, len do
        local div = html:tag("div"):addClass("Lyrics-line")
        
        local emptyline = true -- 是否为空行。
        for i = 1, #versions do
            if (versions[versions[i]].lines[line] or "") ~= "" then
                emptyline = false
            end
        end
        if emptyline then
            div:tag("div")
                :attr("data-column", 1) -- 当前的列编号。
                :attr("data-column-count", 1) -- 列的总数。
                :addClass("Lyrics-column") -- 通用列样式。
                :newline()
        else
            for i = 1, #versions do
                local entry = versions[versions[i]]
                local nlang = lang.wrap(entry.lines[line] or "", entry.lang)
                div:tag("div")
                    :attr("data-column", i) -- 当前的列编号。
                    :attr("data-column-count", #versions) -- 列的总数。
                    :addClass("Lyrics-column") -- 通用列样式。
                    :addClass("Lyrics-column-"..entry.lang) -- 针对语言的样式。
                    :addClass("Lyrics-col"..tostring(i)) -- 针对特定列的样式。
                    :addClass("Lyrics-column-suppressed") -- 宽屏时压缩在一行内的列的样式。
                    :cssText(entry.style)
                    :css("width", "calc(95% / "..tostring(#versions)..")") -- 在一行内放下所有列。
                    :node(nlang)
                div:tag("div")
                    :attr("data-column", i) -- 当前的列编号。
                    :attr("data-column-count", #versions) -- 列的总数。
                    :addClass("Lyrics-column") -- 通用列样式。
                    :addClass("Lyrics-column-"..entry.lang) -- 针对语言的样式。
                    :addClass("Lyrics-col"..tostring(i)) -- 针对特定列的样式。
                    :addClass("Lyrics-column-wrapped") -- 窄屏时拆分为多行的列的样式。
                    :cssText(entry.style)
                    :node(nlang)
            end
        end
    end

    -- Clear the floating
    html:tag("div"):css("clear", "both")

    local css = mw.getCurrentFrame():extensionTag{ name = "templatestyles", args = { src = "Template:LyricsKai/multi/styles.css" } }
    
    return css .. tostring(html)
end

function p.lyrics(frame)
    local args = getArgs(frame, { wrappers = "Template:LyricsKai/multi" })
    return p._lyrics(args)
end

return p