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