banner
Hello!

mediawiki之基于模块的模板

Scroll down

mediawiki之基于模块的模板

时间线模板的最终效果

注:此wiki站使用的版权协议为CC-BY-SA 4.0,相关代码版权以源站为准。

缘起

从参与这个粉丝wiki建设开始,我就想到利用时间线的形式来优化背景信息类条目的叙述。然而我却意外地发现时间线这种东西并没有好用的现成模板,从萌百搬过来的那个是纯文字,其他wiki站上要么没遇见过好用的,要么就是找不到源码。最近又有一位粉丝提出了通过时间线整理漫画剧情的方案,恰好我的那个杀戮尖塔mod项目又处于停顿状态,再加上我在这个wiki站最近的活跃度也不太够,于是就想着自己写一个能用的时间线模板出来。

经过

想要写出一个返回非维基文本的模板,基本都要借助模块。而这样的模板一般都有三部分组成:规定逻辑的模块,引用逻辑的模板和规定样式的样式表。

而这三者分别需要lua、mediawiki和三件套的相关知识。

这里就分别说明这几项。

三件套

在撰写模块之前,我必须先在一个html中先写出类似的效果。而这里并不需要js(逻辑部分是lua那边的事),只需要把静态效果弄出来就可以了。

本以为这应该是一件不难的事(因为之前有过三件套的开发经验),但实际上手起来才发现跟一开始想的不是一回事。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
    <body>
<div class="timeline">
<div class="trunk"></div>
<div class="branch" id="branch-1">
<div class="line">
<span class="id">123话</span>
</div>
<div class="text">
仑负着份韩慧十同仇种希,统说韦的名到是冷人,人但说备不书仆可联妄娘,重揽大头不我重不揽的和们么,而话有一你起的狂上小所事措地,统说韦的名到是冷人
</div>
</div>
<div class="branch" id="branch-2">
<div class="line">
<span class="id">123话</span>
</div>
<div class="text">
仄师用叹拆即,统说韦的名到是冷人
</div>
</div>
<div class="branch" id="branch-3">
<div class="line">
<span class="id">123话</span>
</div>
<div class="text">
对种榜让畴不今仃,雷爱所的可尘位哉国畴蒲火觉才不由少,战生轻韦如没里人谓第人知,太不投吴畴畴得牛我联求卑方不,行不的争死未宋无舟范他非三同,策花德攻水我洪,别夹太与今事派上交非范价,郭法出馆,兴登后洋时一的两会,不有正十之谓绪药定攻音啦死脱降办仍作锐,是。
</div>
</div>

<div class="branch" id="branch-4">
<div class="line">
<span class="id">123话</span>
</div>
<div class="text">
严陀娟自足仄马土是见场他才不会变,办升他德仑而曰动与魂留足在说,娇老害判愚王同上留有帮洋知家学什少了亲,人宫己是,公那尝被谢龄中是放一子二白不,白恨洪狂竟皇县,衣降王司保间判上评有在未商留价后归,活马令国韩耳持一绝光反同同一家,却发要即官文来问德姑绝褒于。
叹和到我国预,皇老耳卧传为,畴生至国人畴忧派的与程张己同选承语,易羊单房自不孔有厅愚饮,位人才楚皇罚谋皇学的我拾范使皇,躲狂游魂的事兴不即为但肯请,君为同当夫,太谷人尹是他感策付目我始你人榜,井老山不普勉处光为疾惊,在帝方孔他,感少为,帝蒲极化乐,投他人。
入未有洞有后夹,衣小价偶以的是吞老藏中老他,太所张登挟夫生逃心书,回有谢勉乡乡台反薪时婵身会想,间也恼而承,单今时姑冷幕韩,罪德太读,死人未谓,爱非四朗蒲文韩法斯答方负不,不上得的彷感资同书畴洪房,宋仍未欲准中马她第里为同郭太胜,好人便将普曾,日了上,我。
</div>
</div>
<div class="emptycell"></div>
</div>
</body>
</html>

html本体也就那么点事,主要的还是css。

在在布局问题上卡了很久之后,最终采用的布局架构是grid嵌套flex。

1
2
3
4
5
6
7
div.timeline {
display: grid;
grid-template-columns: 1fr 1fr;
grid-auto-rows: max-content;
gap: 5px;
position: relative;
}

总体的框架。这里将整个空闲区域分为两列,每一行的宽度取决于其中的最大宽度(但实际上似乎用处不大),每个格子间隔5px。

1
2
3
4
5
6
7
8
9
10
div.trunk {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 50%;
width: 5px;
transform: translateX(-50%);
background-color: black;
}

整个时间线的主干。实际上就是一条黑线,从grid网格的顶部延申到底部。宽设置为5px,transform用于将这条线移到中间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
div.branch {
position: relative;
display: flex;
justify-content: center;
justify-items: end;
align-items: center;
}

div.branch:nth-child(even) {
grid-column-start: -3;
grid-column-end: -2;
justify-content: end;
flex-direction: row-reverse;
}

div.branch:nth-child(odd) {
top: 50px;
grid-column-start: -2;
grid-column-end: -1;
justify-content: start;
}

每个分支对应的区域。这里在分支区域使用了弹性盒布局以方便文字与框——线排布。

偶数位的分支占据右边一列,奇数位的占据左边一列。而弹性盒布局也能利用flex-direction轻松地指定元素左右翻转。同时也为奇偶数位指定分布开始的基准线(justify-content)。

1
2
3
4
5
6
div.line {
position: relative;
background-color: black;
height: 2px;
min-width: 100px;
}

每个分支中的指示线。没什么好说的。

1
2
3
4
5
6
7
8
div.text {
position: relative;
background-color: transparent;
border: 2px solid black;
border-radius: 5px;
max-width: 500px;
padding: 5%;
}

实际的文本框。实际运用时背景被设为了白色。

1
2
3
4
5
6
span.id {
position: relative;
margin-left: 10%;
margin-top: 2px;
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
}

指示线上的文本。这里的span是line的子元素,方便对齐。

1
2
3
4
div.emptycell {
max-height: 5em;
min-height: 3em;
}

占位符。为什么会有这东西?

在实际使用中,弹性盒并不会老老实实地待在网格之中,它对文本的自适应会使得其本身脱离网格范围。

这在单一的网页中并不会导致任何问题,但在实际使用中却出现了严重的出框现象。而这种出框就是因为网格并没有完全包含其中内容。

在许多次尝试之后,最终的解决方案是,在整个结构的最后加入一个空的占位符,这样就能规避出框现象。

在底部加入一个占位符后的效果,可以看出下面多了一行。

至此,网页测试部分基本完成。

模块/模板

这里主要参考的有:mbox模版,navbox模板,以及mw的官方文档

mediawiki的模块是利用lua编写的,而lua也是一项轻量的脚本语言。

而模块——模板方面真正出问题的点并不在lua本身,而是模块——模板的传参问题上。

模板本身的实现非常简单,只需要invoke对应的模块并引用对应样式即可。

1
<includeonly>{{#invoke: Flow-timeline | timeline}}</includeonly><templatestyles src="T:Flow-timeline/style.css" />

如何将模板的参数传到模块中,然后让模块返回内容呢?

首先是返回。

这个模板引用的实际意义是,调用模块Flow-timeline中的timeline函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
--出于兼容性考虑,这里的类名与上文中的有一定出入
local data = {}
local framework={}
local function getId(args)
for key, value in pairs(args) do
local prefix = string.match(key, "(%a+)%d+")
local index = tonumber(string.match(key, "%d"))
if index and not data[index] then
data[index] = {}
end
if prefix == "text" then
data[index][2] = value
elseif prefix == "id" then
data[index][1] = value
end
end
end
function framework.timeline(frame)
local args = frame:getParent().args
getId(args)
local timeline = mw.html.create("div")
timeline:addClass("timeline-framework")
local trunk = mw.html.create("div")
trunk
:addClass("timeline-trunk")
timeline:node(trunk)
for index, value in ipairs(data) do
local branch = mw.html.create("div")
branch
:addClass("timeline-branch")
:attr("id","timeline-branch-" .. index)
timeline:node(branch)
local line = mw.html.create("div")
line
:addClass("timeline-line")
:attr("id","timeline-line-" .. index)
branch:node(line)
if value[1] then
local id = mw.html.create("span")
id
:addClass("timeline-id")
:attr("id","timeline-id-" .. index)
:wikitext(value[1])
line:node(id)
end
if value[2] then
local text = mw.html.create("div")
text
:addClass("timeline-text")
:attr("id","timeline-text-" .. index)
:wikitext(value[2])
branch:node(text)
end
end
local empty=mw.html.create("div")
empty:addClass("timeline-emptycell")
timeline:node(empty)
return tostring(timeline)
end
return framework

在mw的模块中,整体返回的值应该是一个表(return framework),而调用的函数应该是这个表的表函数。

在这个模块中,模板调用的便是表函数timeline。而整个模块实际上整体返回的值便是这个函数返回的值。

在这里,调用函数中使用mw自带的mw.html模块创建html内容,然后整体转为字符串返回就可以了。

那这个函数如何获取模板传入的参数呢?

这个函数的参数只有一个frame,而这个东西实际上就是模板传入的整体信息。而frame.args便是传入的参数表。

然而,这里却有一个很坑的点:

出于性能考虑,frame.args 是一个元数据表,而不是一个真正的参数表。参数值是按需从 MediaWiki 请求的。这意味着大多数其他表格方法将无法正常工作,包括 #frame.args 、 next( frame.args ) 以及 Table 库中的函数。——官方文档

这里如果尝试对args进行遍历,似乎是遍历不出来东西的。。。而这里显然并不需要考虑性能问题(因为所有的参数都迟早会被调用),所以这里使用frame:getParent().args来得到一个真正的参数表,这样就可以正常地进行遍历了。

结果

最终这个模板已经在这个wiki站投入使用,虽然还有一些bug(如移动端可能的显示问题),但至少能用了,效果如置顶图所示。

最终感想:css创始人,你睡了吗?我睡不着

其他文章
目录导航 置顶
  1. 1. mediawiki之基于模块的模板
    1. 1.1. 缘起
    2. 1.2. 经过
      1. 1.2.1. 三件套
      2. 1.2.2. 模块/模板
    3. 1.3. 结果