置顶公告:【置顶】关于临时开启评论区所有功能的公告(2022.10.22) | 【置顶】关于本站Widget恢复使用的公告
  • 你好~!欢迎来到萌娘百科镜像站!如需查看或编辑,请联系本站管理员注册账号。
  • 本镜像站和其他萌娘百科的镜像站无关,请注意分别。

Module:Clade

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

本模板用于绘制树。

简易语法

只传入匿名参数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
枝a-a叶子a-1
 
枝a-b叶子a-2
 
枝a-c
枝a-c-a叶子a-c-1
 
枝a-c-b叶子a-c-2
 
 
 
枝b叶子2
 
  1. local getArgs = require('Module:Arguments').getArgs
  2. local insert = table.insert
  3. local format = string.format
  4. local match = string.match
  5. local p = {}
  6. --[[- 返回node。
  7. node是一张表,结构为 {
  8. label = '',
  9. node1,
  10. node2,
  11. ...
  12. }
  13. ]]
  14. local function Node(label, ...)
  15. return {
  16. label = label,
  17. ...
  18. }
  19. end
  20. --[=[- 预处理传入的字符串,返回一个数组,每个元素为{深度, 文字}的形式,其中树根的深度为1。
  21. 例如:
  22. preprocessLines([[
  23. Root
  24. * A
  25. ** A1
  26. * B
  27. ]])
  28. 将返回
  29. {
  30. {1, 'Root'},
  31. {2, 'A'},
  32. {3, 'A1'},
  33. {2, 'B'}
  34. }
  35. ]=]
  36. local function preprocessLines(raw)
  37. local lines = {}
  38. for rawLine in string.gmatch(raw..'\n', '([^\n]+)\n') do
  39. insert(lines, {match(rawLine, '^%**()%s*(.-)%s*$')})
  40. end
  41. return lines
  42. end
  43. --- 给传入的node用depth个父结点包装,返回包装最外层的结点。
  44. -- depth == 0时,返回原node。
  45. local function wrapNode(node, depth)
  46. local wrappedNode = node
  47. for i = 1, depth do
  48. wrappedNode = Node('', wrappedNode)
  49. end
  50. return wrappedNode
  51. end
  52. --[=[- 创建森林。
  53. 例如:
  54. Forest([[
  55. Root
  56. * A
  57. ** A1
  58. * B
  59. ]])
  60. 将返回
  61. {
  62. label = nil,
  63. {
  64. label = 'Root',
  65. {
  66. label = 'A',
  67. {
  68. label = 'A1'
  69. }
  70. },
  71. {
  72. label = 'B'
  73. }
  74. }
  75. }
  76. ]=]
  77. local function Forest(raw)
  78. local lines = preprocessLines(raw)
  79. local lineNumber = 1 -- 被多个generateBranch函数共享状态
  80. --- 构建指定层数的树枝
  81. -- 返回一个表,包含其树枝
  82. local function generateBranch(depth, label)
  83. local branch = Node(label)
  84. local curLine = lines[lineNumber]
  85. while curLine do
  86. local curDepth, curText = curLine[1], curLine[2]
  87. if curDepth <= depth then
  88. return branch
  89. end
  90. -- 当前行深度 > depth
  91. lineNumber = lineNumber + 1
  92. insert(branch, wrapNode(generateBranch(curDepth, curText), curDepth - depth - 1))
  93. curLine = lines[lineNumber]
  94. end
  95. return branch
  96. end
  97. return generateBranch(0)
  98. end
  99. --[[- 将分支(或叶子)递归地转为HTML。返回2个值:html字符串, 参数是否为叶子
  100. node = {
  101. label = 'A',
  102. {
  103. label = '1',
  104. {
  105. label = 'a'
  106. }
  107. },
  108. {
  109. label = '2'
  110. },
  111. {
  112. label = '3'
  113. }
  114. }
  115. 即:
  116. 1
  117. +-- a
  118. A |
  119. ---+-- 2
  120. |
  121. +-- 3
  122. 返回
  123. <div class="clade-branch">
  124. <div class="clade-label">1</div>
  125. <div class="clade-leaf">a</div>
  126. <div class="clade-space"></div>
  127. <div class="clade-label"></div>
  128. <div class="clade-leaf">2</div>
  129. <div class="clade-space"></div>
  130. <div class="clade-label"></div>
  131. <div class="clade-leaf">3</div>
  132. <div class="clade-space"></div>
  133. </div>
  134. ]]
  135. local function branchToHtml(branch)
  136. if not branch[1] then
  137. return '<div class="clade-leaf">' .. branch.label .. '</div>', true
  138. end
  139. local htmlParts = {}
  140. for i, subNode in ipairs(branch) do
  141. local subHtml, subNodeIsLeaf = branchToHtml(subNode)
  142. if subNodeIsLeaf and not branch[2] then
  143. return subHtml, false
  144. end
  145. htmlParts[i] = format(
  146. '<div class="clade-label">%s</div>%s<div class="clade-space"></div>',
  147. subNodeIsLeaf and '' or subNode.label,
  148. subHtml
  149. )
  150. end
  151. return '<div class="clade-branch">'..table.concat(htmlParts)..'</div>', false
  152. end
  153. local function forestToHtml(forest)
  154. local html = {}
  155. for i, tree in ipairs(forest) do
  156. html[i] = branchToHtml({tree})
  157. end
  158. return table.concat(html)
  159. end
  160. function p.fromString(raw)
  161. return forestToHtml(Forest(raw))
  162. end
  163. function p.main(frame)
  164. local args = getArgs(frame)
  165. return p._main(args)
  166. end
  167. function p._main(args)
  168. -- 版本判断
  169. local version = 2 -- 2023-12-03前的语法为version 1,之后的新语法为version 2
  170. for k, v in pairs(args) do
  171. if k ~= 1 then
  172. version = 1
  173. break
  174. end
  175. end
  176. if version == 2 then
  177. return p.fromString(args[1])
  178. end
  179. local clade = mw.html.create('div'):addClass('clade-wrapper') -- 外围容器
  180. local space = '<span class="clade-space">&nbsp;</span>'
  181. if args['root'] then
  182. clade
  183. :tag('div'):addClass('clade-root') -- 根节点
  184. :tag('div'):addClass('clade-root-1'):wikitext(args['root'] or ''):done()
  185. :tag('div'):addClass('clade-root-2 clade-space'):wikitext('&nbsp;')
  186. end
  187. local cladeTable = clade:tag('table'):addClass('clade-table') -- 叶子部分
  188. local i = 1
  189. while args[i] or args['label' .. i] do -- 循环生成。边框什么的交给CSS,懒得写判断了
  190. cladeTable
  191. :tag('tr')
  192. :tag('td'):addClass('clade-label'):wikitext(args['label' .. i] or space):done()
  193. :tag('td'):attr('rowspan', '2'):wikitext(args[i] or ""):done()
  194. :done()
  195. :tag('tr')
  196. :tag('td'):addClass('clade-space'):wikitext('&nbsp;')
  197. i = i + 1
  198. end
  199. return clade
  200. end
  201. return p