Module:Clade
跳到导航
跳到搜索
本模板用于绘制树。
简易语法
只传入匿名参数1
以使用简易语法。传入其他任何参数将被认为是复杂语法。
在简易语法中,每行写一个结点,以*
区分层级,类似wikitext的无序列表。
{{clade|1= 树1 * 枝1 ** 枝1-1 *** 叶子1-1-1(可以写''wikitext'',但'''不能'''跨行) ** 枝1-2 *** 叶1-2-1(可以嵌套{{color|#161|单行模板}}) ** 枝1-3 *** 枝1-3-1 **** 叶1-3-1-1 *** 枝1-3-2 **** 叶1-2-2-1 * 枝2 ** 叶2-1 树2 * 可以写多个树 * …… }}
树1
枝1
枝1-1
叶子1-1-1(可以写wikitext,但不能跨行)
枝1-2
叶1-2-1(可以嵌套单行模板)
枝1-3
枝1-3-1
叶1-3-1-1
枝1-3-2
叶1-2-2-1
枝2
叶2-1
树2
可以写多个树
……
复杂语法
参数
root
:根节点内容labelx
:第x个叶子节点上的分支标签,label1、label2以此类推。- 匿名参数
x
:第x个叶子节点的内容。
参数都不是必须,可以留空,会自动根据输入的情况生成。
用例
使用所有参数:
{{clade |root=根 |label1=枝a |1=叶子1 |label2=枝b |2=叶子2 |label3=枝c |3=叶子3 |label4=枝c |4=叶子3 }}
根
枝a | 叶子1 |
枝b | 叶子2 |
枝c | 叶子3 |
枝d | 叶子4 |
使用部分参数:
{{clade |1=叶子1 |2=叶子2 |3=叶子3 |label4=枝d }}
叶子1 | |
叶子2 | |
叶子3 | |
枝d | |
嵌套使用生成多级子树:
需要生成多级子树时,子树不建议输入root参数,容易出现错误。
{{clade |root=根 |label1=枝a |1={{clade |label1=枝a-a |1=叶子a-1 |label2=枝a-b |2=叶子a-2 |label3=枝a-c |3={{clade |label1=枝a-c-a |1=叶子a-c-1 |label2=枝a-c-b |2=叶子a-c-2 }} }} |label2=枝b |2=叶子2 }}
根
枝a |
| |||||||||||||||
枝b | 叶子2 | |||||||||||||||
local getArgs = require('Module:Arguments').getArgs local insert = table.insert local format = string.format local match = string.match local p = {} --[[- 返回node。 node是一张表,结构为 { label = '', node1, node2, ... } ]] local function Node(label, ...) return { label = label, ... } end --[=[- 预处理传入的字符串,返回一个数组,每个元素为{深度, 文字}的形式,其中树根的深度为1。 例如: preprocessLines([[ Root * A ** A1 * B ]]) 将返回 { {1, 'Root'}, {2, 'A'}, {3, 'A1'}, {2, 'B'} } ]=] local function preprocessLines(raw) local lines = {} for rawLine in string.gmatch(raw..'\n', '([^\n]+)\n') do insert(lines, {match(rawLine, '^%**()%s*(.-)%s*$')}) end return lines end --- 给传入的node用depth个父结点包装,返回包装最外层的结点。 -- depth == 0时,返回原node。 local function wrapNode(node, depth) local wrappedNode = node for i = 1, depth do wrappedNode = Node('', wrappedNode) end return wrappedNode end --[=[- 创建森林。 例如: Forest([[ Root * A ** A1 * B ]]) 将返回 { label = nil, { label = 'Root', { label = 'A', { label = 'A1' } }, { label = 'B' } } } ]=] local function Forest(raw) local lines = preprocessLines(raw) local lineNumber = 1 -- 被多个generateBranch函数共享状态 --- 构建指定层数的树枝 -- 返回一个表,包含其树枝 local function generateBranch(depth, label) local branch = Node(label) local curLine = lines[lineNumber] while curLine do local curDepth, curText = curLine[1], curLine[2] if curDepth <= depth then return branch end -- 当前行深度 > depth lineNumber = lineNumber + 1 insert(branch, wrapNode(generateBranch(curDepth, curText), curDepth - depth - 1)) curLine = lines[lineNumber] end return branch end return generateBranch(0) end --[[- 将分支(或叶子)递归地转为HTML。返回2个值:html字符串, 参数是否为叶子 node = { label = 'A', { label = '1', { label = 'a' } }, { label = '2' }, { label = '3' } } 即: 1 +-- a A | ---+-- 2 | +-- 3 返回 <div class="clade-branch"> <div class="clade-label">1</div> <div class="clade-leaf">a</div> <div class="clade-space"></div> <div class="clade-label"></div> <div class="clade-leaf">2</div> <div class="clade-space"></div> <div class="clade-label"></div> <div class="clade-leaf">3</div> <div class="clade-space"></div> </div> ]] local function branchToHtml(branch) if not branch[1] then return '<div class="clade-leaf">' .. branch.label .. '</div>', true end local htmlParts = {} for i, subNode in ipairs(branch) do local subHtml, subNodeIsLeaf = branchToHtml(subNode) if subNodeIsLeaf and not branch[2] then return subHtml, false end htmlParts[i] = format( '<div class="clade-label">%s</div>%s<div class="clade-space"></div>', subNodeIsLeaf and '' or subNode.label, subHtml ) end return '<div class="clade-branch">'..table.concat(htmlParts)..'</div>', false end local function forestToHtml(forest) local html = {} for i, tree in ipairs(forest) do html[i] = branchToHtml({tree}) end return table.concat(html) end function p.fromString(raw) return forestToHtml(Forest(raw)) end function p.main(frame) local args = getArgs(frame) return p._main(args) end function p._main(args) -- 版本判断 local version = 2 -- 2023-12-03前的语法为version 1,之后的新语法为version 2 for k, v in pairs(args) do if k ~= 1 then version = 1 break end end if version == 2 then return p.fromString(args[1]) end local clade = mw.html.create('div'):addClass('clade-wrapper') -- 外围容器 local space = '<span class="clade-space"> </span>' if args['root'] then clade :tag('div'):addClass('clade-root') -- 根节点 :tag('div'):addClass('clade-root-1'):wikitext(args['root'] or ''):done() :tag('div'):addClass('clade-root-2 clade-space'):wikitext(' ') end local cladeTable = clade:tag('table'):addClass('clade-table') -- 叶子部分 local i = 1 while args[i] or args['label' .. i] do -- 循环生成。边框什么的交给CSS,懒得写判断了 cladeTable :tag('tr') :tag('td'):addClass('clade-label'):wikitext(args['label' .. i] or space):done() :tag('td'):attr('rowspan', '2'):wikitext(args[i] or ""):done() :done() :tag('tr') :tag('td'):addClass('clade-space'):wikitext(' ') i = i + 1 end return clade end return p