此模块作为模板{{Utawari}}的背后实现,主要用于简便地书写歌割り对齐的歌词。
在仅有不超过9句歌割り歌词时,建议使用模板{{Utawari}}。
根据2018年11月19日-2018年11月22日关于宽屏/窄屏缩进行为的讨论,目前的效果为:
使用格式:
{{#invoke:Utawari[|noLyric=][|lineSeparator=][|第1行歌词[|第2行歌词|...[|第n行歌词]]]}}
{{#invoke:Utawari[|noLyric=][|lineSeparator=][|
第1行歌词[|
第2行歌词[|
...[|
第n行歌词]]]
}}
lyricMode:是否开启歌词模式。歌词模式详见#歌词模式与#非歌词模式章节。
lineSeparator:模块的自定义换行字符串。
此模块的功能与用法与模板{{Utawari}}基本相同。建议仅当歌割り中歌词超过9句时使用本模块。
更多详细用法请见:模板:Utawari/doc。
lineSeparator参数。lyricMode参数。Utawari这个名称来使用模版了。local module = {};
local noLyric = false;
local getArgs = require('Module:Arguments').getArgs
function module.main(frame)
local args = getArgs(frame)
return module._main(args)
end
function module._main(args)
local nodes = {}
for i, v in ipairs(args) do table.insert(nodes, module.createNode()) end --初始化结果table。
-- 建立引用树。
for i, v in ipairs(args) do
module.analyzeLine(i, v, nodes)
end
local lineSeparator = nil
if args["noLyric"] == nil then --歌词模式
noLyric = false
lineSeparator = "\r\n" --{{LyricsKai}}/{{LyricsKai/colors}}中的换行字符串。
else --非歌词模式
noLyric = true
lineSeparator = args["lineSeparator"]
if lineSeparator == nil then
lineSeparator = "\r\n\r\n" --wiki的换行字符串。
end
end
return module.output(nodes, lineSeparator)
end
function module.analyzeLine(index, line, result)
local currentNode = result[index]
local r = module.stringSplitX(line, "##|#%d+",
function(t, i, l)
if (t == "##") then
return "#"
else
local referenceNode = result[tonumber(string.sub(t, 2, l))]
module.setParent(referenceNode, currentNode)
return referenceNode
end
end
)
for i,v in ipairs(r) do
table.insert(currentNode.data, v)
end
end
function module.output(nodes, lineSeparator)
local result = {}
local outputLine = function(node)
local outputTabInternal = nil
outputTabInternal = function(n, t)
if (n.parent == nil) then return end
outputTabInternal(n.parent, t)
for _i, _d in ipairs(n.parent.data) do
if _d == n then break
elseif module.tableFind(nodes, _d) ~= nil then --Do nothing.
else
table.insert(t, _d)
end
end
end
local tabs = {}
outputTabInternal(node, tabs)
local datas = {}
for i, d in ipairs(node.data) do
if module.tableFind(nodes, d) == nil then
table.insert(datas, d)
end
end
if next(tabs) == nil then
table.insert(result, table.concat(datas))
else
local span = mw.html.create("span")
-- span:attr("class", "mw-parser-output")
local sub = mw.html.create("span")
if noLyric then
sub:attr("class", "Utawari-nolyric-tab") --非歌词模式使用的样式。
else
sub:attr("class", "Utawari-lyric-tab") --歌词模式使用的样式。
end
sub:node(table.concat(tabs))
span:node(sub) span:node(table.concat(datas))
table.insert(result, tostring(span))
end
end
for i, v in ipairs(nodes) do outputLine(v) end
return table.concat(result, lineSeparator)
end
--判断node1是否为node2的上层节点。
function module.isAncestor(node1, node2)
if node2.parent == nil then
return false
elseif node2.parent == mode1 then
return true
else
return module.isAncestor(node1, node2.parent)
end
end
--将node2设为node1的父节点。
function module.setParent(node1, node2)
if node1.parent ~= nil then error("无法修改父节点。")
elseif module.isAncestor(node1, node2) then error("循环设置父节点。")
else
node1.parent = node2
table.insert(node2.children, node1)
end
end
--创建一个新节点。
function module.createNode()
return {
parent = nil,
children = {},
data = {}
}
end
function module.stringSplitX(s, pattern, func)
local result = {}
local localIndex = 1
while true do
local text, index, length = module.stringMatchX(s, pattern, localIndex)
if index == nil then break end
if index > localIndex then table.insert(result, string.sub(s, localIndex, index - 1)) end
table.insert(result, func(text, index, length))
localIndex = index + length
end
if localIndex <= string.len(s) then table.insert(result, string.sub(s, localIndex, string.len(s))) end
return result;
end
function module.stringMatchX(s, pattern, init)
local x, y = module.stringFindX(s, pattern, init)
if x == nil or y == nil then
return nil, nil, nil
else
local text = string.sub(s, x, y)
local length = y - x + 1
return text, x, length
end
end
function module.stringFindX(str, pattern, init)
local va1, va2 = string.find(pattern, "|")
local patterntable = {}
if va1 ~= nil then
table.insert(patterntable, string.sub(pattern, 1, va1 - 1))
table.insert(patterntable, string.sub(pattern, va1 + 1, string.len(pattern)))
end
va1, va2 = string.find(str, patterntable[1], init)
if va1 == nil then return string.find(str, patterntable[2], init)
else
va3, va4 = string.find(str, patterntable[2], init)
if va3 == nil then return va1, va2 end
if va1 < va3 then return va1, va2
elseif va1 > va3 then return va3, va4
else
if va2 <= va4 then return va1, va2
else return va3, va4
end
end
end
return va1, va2
end
function module.tableFind(t, item)
for i,v in ipairs(t) do
if v == item then return i end
end
return nil
end
return module