2023年政策修订增补工作正在进行中,欢迎参与!
  • Moegirl.ICU:萌娘百科流亡社群 581077156(QQ),欢迎对萌娘百科运营感到失望的编辑者加入
  • Moegirl.ICU:账号认领正在试运行,有意者请参照账号认领流程

Module:Utawari

萌娘百科,万物皆可萌的百科全书!转载请标注来源页面的网页链接,并声明引自萌娘百科。内容不可商用。
跳转到导航 跳转到搜索
Template-info.svg 模块文档  [查看] [编辑] [历史] [刷新]

简介

此模块作为模板{{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行歌词]]]
}}

用法

此模块的功能与用法与模板{{Utawari}}基本相同。建议仅当歌割り中歌词超过9句时使用本模块。

更多详细用法请见:模板:Utawari/doc

贡献者

版本历史

Template-info.svg 模块版本历史  [查看] [编辑] [历史] [刷新]
  • 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