2023年政策修订增补工作正在进行中,欢迎参与!
Module:Utawari
跳转到导航
跳转到搜索
简介
此模块作为模板{{Utawari}}的背后实现,主要用于简便地书写歌割り对齐的歌词。
在仅有不超过9句歌割り歌词时,建议使用模板{{Utawari}}。
根据2018年11月19日-2018年11月22日关于宽屏/窄屏缩进行为的讨论,目前的效果为:
- 歌词模式下:
- 宽屏设备浏览时显示缩进;
- 窄屏设备浏览时隐藏缩进。
- 非歌词模式下:
- 宽屏/窄屏设备浏览时均显示缩进。
参数
使用格式:
{{#invoke:Utawari[|noLyric=][|lineSeparator=][|第1行歌词[|第2行歌词|...[|第n行歌词]]]}}
- 或者更加直观易读且在原{{LyricsKai}}/{{LyricsKai/colors}}基础上改动最小的格式:
{{#invoke:Utawari[|noLyric=][|lineSeparator=][| 第1行歌词[| 第2行歌词[| ...[| 第n行歌词]]] }}
lyricMode
:是否开启歌词模式。歌词模式详见#歌词模式与#非歌词模式章节。lineSeparator
:模块的自定义换行字符串。- (默认)当值为空时,等同于值为两个“
回车换行符( )”。
- (默认)当值为空时,等同于值为两个“
(各行歌词)( ) = 歌割中的和声部分。这部分参数兼容{{LyricsKai}}/{{LyricsKai/colors}}的使用格式,更高阶的拓展格式请见模板:Utawari/doc#用法章节。
用法
此模块的功能与用法与模板{{Utawari}}基本相同。建议仅当歌割り中歌词超过9句时使用本模块。
更多详细用法请见:模板:Utawari/doc。
贡献者
- サンムル[更多]
- Nzh21[更多]
- 迟昫123[更多]
- Silverpearl[更多]
版本历史
- 2018年11月19日 (一) 02:05 代码本地测试通过。模块基础逻辑在本地测试通过,上传调试。
- 2018年11月19日 (一) 03:01 用span标签替换模板输出。输出内容中包含的wiki文本(模版)无法解析,使用HTML的span标签替换,实现等价效果。
- 2018年11月19日 (一) 03:01 添加对用户定制换行字符串功能的支持。增设
lineSeparator
参数。 - 2018年11月19日 (一) 15:57 区分歌词模式和非歌词模式的换行行为;修复了不能同时识别标志“#n”和转义“##”的问题。增设
lyricMode
参数。 - 2018年11月19日 (一) 17:39 模版转正现在可以通过
Utawari
这个名称来使用模版了。 - 2018年11月22日 (四) 00:09 添加对TemplateStyles的支持。依循TemplateStyles格式重构输出代码。添加歌词模式下的缩进在宽屏时显示、窄屏时隐藏的功能。
- 2018年11月22日 (四) 21:16 使用mw.html库重写部分逻辑。舍弃字符串硬编写HTML源代码,使用类似创建DOM的形式重构输出代码。
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