laporan-generator 2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/laporan-generator/SKILL.md +132 -0
- package/.agents/skills/laporan-generator/agents/openai.yaml +3 -0
- package/.agents/skills/laporan-generator/references/campus-guide.md +120 -0
- package/.agents/skills/laporan-generator/references/metadata-schema.md +76 -0
- package/.agents/skills/laporan-generator/references/preset-schema.md +79 -0
- package/.agents/skills/laporan-generator/references/syntax-cheatsheet.md +122 -0
- package/.agents/skills/laporan-generator/references/template-guide.md +100 -0
- package/.agents/skills/laporan-generator/references/troubleshooting.md +105 -0
- package/.agents/skills/laporan-generator/resources/Makefile +90 -0
- package/.agents/skills/laporan-generator/resources/apa.csl +2273 -0
- package/.agents/skills/laporan-generator/resources/build-docx.sh +122 -0
- package/.agents/skills/laporan-generator/resources/build.sh +102 -0
- package/.agents/skills/laporan-generator/resources/chapters/bab1-pendahuluan.md +60 -0
- package/.agents/skills/laporan-generator/resources/chapters/bab2-tinjauan-pustaka.md +83 -0
- package/.agents/skills/laporan-generator/resources/chapters/bab3-metodologi.md +116 -0
- package/.agents/skills/laporan-generator/resources/chapters/bab4-hasil-dan-pembahasan.md +93 -0
- package/.agents/skills/laporan-generator/resources/chapters/bab5-penutup.md +27 -0
- package/.agents/skills/laporan-generator/resources/cover.md +50 -0
- package/.agents/skills/laporan-generator/resources/docx.lua +416 -0
- package/.agents/skills/laporan-generator/resources/laporan +464 -0
- package/.agents/skills/laporan-generator/resources/laporan.ps1 +552 -0
- package/.agents/skills/laporan-generator/resources/logo.jpg +0 -0
- package/.agents/skills/laporan-generator/resources/metadata.yml +35 -0
- package/.agents/skills/laporan-generator/resources/presets/itb-ta.yml +27 -0
- package/.agents/skills/laporan-generator/resources/presets/its-skripsi.yml +26 -0
- package/.agents/skills/laporan-generator/resources/presets/skripsi-4433.yml +26 -0
- package/.agents/skills/laporan-generator/resources/presets/standard.yml +26 -0
- package/.agents/skills/laporan-generator/resources/presets/ugm-skripsi.yml +26 -0
- package/.agents/skills/laporan-generator/resources/presets/ui-skripsi.yml +26 -0
- package/.agents/skills/laporan-generator/resources/presets/unpad-skripsi.yml +27 -0
- package/.agents/skills/laporan-generator/resources/reference.docx +0 -0
- package/.agents/skills/laporan-generator/resources/references.bib +115 -0
- package/.agents/skills/laporan-generator/resources/scripts/bundle.py +75 -0
- package/.agents/skills/laporan-generator/resources/scripts/docx-pagenum.py +192 -0
- package/.agents/skills/laporan-generator/resources/scripts/finalize-docx.py +291 -0
- package/.agents/skills/laporan-generator/resources/scripts/make-reference-docx.py +670 -0
- package/.agents/skills/laporan-generator/resources/scripts/report-doctor.py +211 -0
- package/.agents/skills/laporan-generator/resources/scripts/report-stats.py +149 -0
- package/.agents/skills/laporan-generator/resources/scripts/scan-preset.py +311 -0
- package/.agents/skills/laporan-generator/resources/scripts/setup-deps.ps1 +152 -0
- package/.agents/skills/laporan-generator/resources/scripts/setup-deps.sh +113 -0
- package/.agents/skills/laporan-generator/resources/scripts/test_scripts.py +128 -0
- package/.agents/skills/laporan-generator/resources/scripts/validate-preset.py +166 -0
- package/.agents/skills/laporan-generator/resources/template.typ +394 -0
- package/.agents/skills/laporan-generator/scripts/build.sh +78 -0
- package/.agents/skills/laporan-generator/scripts/bundle.py +75 -0
- package/.agents/skills/laporan-generator/scripts/docx-pagenum.py +192 -0
- package/.agents/skills/laporan-generator/scripts/finalize-docx.py +152 -0
- package/.agents/skills/laporan-generator/scripts/laporan +447 -0
- package/.agents/skills/laporan-generator/scripts/laporan.ps1 +529 -0
- package/.agents/skills/laporan-generator/scripts/make-reference-docx.py +630 -0
- package/.agents/skills/laporan-generator/scripts/report-doctor.py +211 -0
- package/.agents/skills/laporan-generator/scripts/report-stats.py +149 -0
- package/.agents/skills/laporan-generator/scripts/scan-preset.py +311 -0
- package/.agents/skills/laporan-generator/scripts/setup-deps.ps1 +152 -0
- package/.agents/skills/laporan-generator/scripts/setup-deps.sh +113 -0
- package/.agents/skills/laporan-generator/scripts/test_scripts.py +103 -0
- package/.agents/skills/laporan-generator/scripts/validate-preset.py +166 -0
- package/.agents/workflows/laporan-generator.md +8 -0
- package/LICENSE +21 -0
- package/Makefile +90 -0
- package/README.md +389 -0
- package/apa.csl +2273 -0
- package/bin/laporan-generator.js +71 -0
- package/build-docx.sh +122 -0
- package/build.sh +102 -0
- package/chapters/bab1-pendahuluan.md +60 -0
- package/chapters/bab2-tinjauan-pustaka.md +83 -0
- package/chapters/bab3-metodologi.md +116 -0
- package/chapters/bab4-hasil-dan-pembahasan.md +93 -0
- package/chapters/bab5-penutup.md +27 -0
- package/cover.md +50 -0
- package/docs/campus-guide.md +120 -0
- package/docs/metadata-schema.md +76 -0
- package/docs/preset-schema.md +79 -0
- package/docs/syntax-cheatsheet.md +122 -0
- package/docs/template-guide.md +100 -0
- package/docs/troubleshooting.md +105 -0
- package/docx.lua +416 -0
- package/laporan +464 -0
- package/laporan.ps1 +552 -0
- package/lib/init.js +118 -0
- package/lib/setup.js +33 -0
- package/lib/sync-hosts.js +194 -0
- package/lib/uninstall.js +123 -0
- package/logo.jpg +0 -0
- package/metadata.yml +35 -0
- package/package.json +65 -0
- package/presets/itb-ta.yml +27 -0
- package/presets/its-skripsi.yml +26 -0
- package/presets/skripsi-4433.yml +26 -0
- package/presets/standard.yml +26 -0
- package/presets/ugm-skripsi.yml +26 -0
- package/presets/ui-skripsi.yml +26 -0
- package/presets/unpad-skripsi.yml +27 -0
- package/reference.docx +0 -0
- package/references.bib +115 -0
- package/scripts/bundle.py +75 -0
- package/scripts/docx-pagenum.py +192 -0
- package/scripts/finalize-docx.py +291 -0
- package/scripts/make-reference-docx.py +670 -0
- package/scripts/report-doctor.py +211 -0
- package/scripts/report-stats.py +149 -0
- package/scripts/scan-preset.py +311 -0
- package/scripts/setup-deps.ps1 +152 -0
- package/scripts/setup-deps.sh +113 -0
- package/scripts/test_scripts.py +128 -0
- package/scripts/validate-preset.py +166 -0
- package/template.typ +394 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# KATA PENGANTAR {-}
|
|
2
|
+
|
|
3
|
+
Puji syukur kehadirat Tuhan Yang Maha Esa atas segala rahmat dan karunia-Nya sehingga laporan yang berjudul **"Otomatisasi Pembuatan Dokumen Laporan Akademik menggunakan Pandoc, Typst, dan Markdown"** dapat diselesaikan dengan baik.
|
|
4
|
+
|
|
5
|
+
Laporan ini disusun sebagai dokumentasi pipeline otomatisasi dokumen akademik yang dibangun menggunakan kombinasi teknologi Markdown, Pandoc, Typst, ImageMagick, dan Bash. Pipeline ini memungkinkan penulisan konten laporan dalam format Markdown yang sederhana, yang kemudian dikonversi menjadi PDF dengan format profesional melalui Pandoc dan Typst.
|
|
6
|
+
|
|
7
|
+
Penulis menyadari bahwa laporan ini tidak dapat terselesaikan tanpa bantuan dari berbagai pihak. Oleh karena itu, penulis mengucapkan terima kasih kepada semua pihak yang telah memberikan dukungan dalam penyelesaian laporan ini.
|
|
8
|
+
|
|
9
|
+
Penulis menyadari bahwa laporan ini masih jauh dari sempurna. Oleh karena itu, kritik dan saran yang membangun sangat diharapkan untuk perbaikan di masa mendatang. Semoga laporan ini dapat memberikan manfaat bagi pembaca dalam memahami konsep otomatisasi dokumen akademik.
|
|
10
|
+
|
|
11
|
+
```{=typst}
|
|
12
|
+
#v(0.8cm)
|
|
13
|
+
#align(right)[
|
|
14
|
+
Agustus 2026
|
|
15
|
+
|
|
16
|
+
#v(1cm)
|
|
17
|
+
Tim Penyusun
|
|
18
|
+
]
|
|
19
|
+
#pagebreak()
|
|
20
|
+
#outline(
|
|
21
|
+
title: [#align(center)[#text(size: 14pt, weight: "bold")[DAFTAR ISI]]],
|
|
22
|
+
depth: 3,
|
|
23
|
+
)
|
|
24
|
+
#context {
|
|
25
|
+
let imgs = query(figure.where(kind: image))
|
|
26
|
+
if imgs.len() > 0 {
|
|
27
|
+
pagebreak()
|
|
28
|
+
outline(
|
|
29
|
+
title: align(center)[#text(size: 14pt, weight: "bold")[DAFTAR GAMBAR]],
|
|
30
|
+
target: figure.where(kind: image),
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
let tbls = query(figure.where(kind: table))
|
|
34
|
+
if tbls.len() > 0 {
|
|
35
|
+
pagebreak()
|
|
36
|
+
outline(
|
|
37
|
+
title: align(center)[#text(size: 14pt, weight: "bold")[DAFTAR TABEL]],
|
|
38
|
+
target: figure.where(kind: table),
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
#pagebreak()
|
|
43
|
+
#set page(numbering: "1")
|
|
44
|
+
#counter(page).update(1)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```{=openxml}
|
|
48
|
+
<w:p><w:pPr><w:jc w:val="right"/><w:spacing w:before="454"/></w:pPr><w:r><w:t>Agustus 2026</w:t></w:r></w:p>
|
|
49
|
+
<w:p><w:pPr><w:jc w:val="right"/><w:spacing w:before="567"/></w:pPr><w:r><w:t>Tim Penyusun</w:t></w:r></w:p>
|
|
50
|
+
```
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
-- docx.lua: penomoran heading dan cover page untuk output DOCX.
|
|
2
|
+
-- - Heading 1: "BAB I PENDAHULUAN" (huruf kapital, angka romawi)
|
|
3
|
+
-- - Heading 2: "1.1. Sub Bab" (titik di akhir nomor)
|
|
4
|
+
-- - Heading 3: "1.1.1 Sub Sub Bab"
|
|
5
|
+
-- - Heading dengan atribut {-} (unnumbered) dilewati tanpa penomoran.
|
|
6
|
+
-- - Cover page dibangun dari metadata (logo, judul, penulis, institusi)
|
|
7
|
+
-- meniru cover PDF, menggantikan title block bawaan pandoc.
|
|
8
|
+
--
|
|
9
|
+
-- Dipakai lewat `pandoc ... --lua-filter=docx.lua --reference-doc=reference.docx`.
|
|
10
|
+
|
|
11
|
+
local bab = 0
|
|
12
|
+
local sub = 0
|
|
13
|
+
local subsub = 0
|
|
14
|
+
local toc_entries = {}
|
|
15
|
+
local chapter_prefix = "BAB "
|
|
16
|
+
local chapter_num_fmt = "roman"
|
|
17
|
+
|
|
18
|
+
local function is_unnumbered(el)
|
|
19
|
+
for _, cls in ipairs(el.attr.classes or {}) do
|
|
20
|
+
if cls == "unnumbered" then
|
|
21
|
+
return true
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
return false
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
local function roman(n)
|
|
28
|
+
local map = {
|
|
29
|
+
{1000, "M"}, {900, "CM"}, {500, "D"}, {400, "CD"},
|
|
30
|
+
{100, "C"}, {90, "XC"}, {50, "L"}, {40, "XL"},
|
|
31
|
+
{10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"},
|
|
32
|
+
}
|
|
33
|
+
local out = ""
|
|
34
|
+
for _, pair in ipairs(map) do
|
|
35
|
+
while n >= pair[1] do
|
|
36
|
+
out = out .. pair[2]
|
|
37
|
+
n = n - pair[1]
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
return out
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
local function balance_title(text)
|
|
44
|
+
local words = {}
|
|
45
|
+
for w in text:gmatch("%S+") do
|
|
46
|
+
words[#words + 1] = w
|
|
47
|
+
end
|
|
48
|
+
local n = #words
|
|
49
|
+
if n <= 1 or #text <= 55 then
|
|
50
|
+
return { text }
|
|
51
|
+
end
|
|
52
|
+
local function count_words(s)
|
|
53
|
+
local c = 0
|
|
54
|
+
for _ in s:gmatch("%S+") do
|
|
55
|
+
c = c + 1
|
|
56
|
+
end
|
|
57
|
+
return c
|
|
58
|
+
end
|
|
59
|
+
local function best_for(k)
|
|
60
|
+
local best, best_cost = nil, math.huge
|
|
61
|
+
local function rec(i, kk, cur, mx, single)
|
|
62
|
+
if kk == 1 then
|
|
63
|
+
local line = table.concat(words, " ", i, n)
|
|
64
|
+
local lines = {}
|
|
65
|
+
for _, l in ipairs(cur) do
|
|
66
|
+
lines[#lines + 1] = l
|
|
67
|
+
end
|
|
68
|
+
lines[#lines + 1] = line
|
|
69
|
+
local m = math.max(mx, #line)
|
|
70
|
+
local s = single + (count_words(line) <= 1 and 1 or 0)
|
|
71
|
+
local cost = m + 100 * s
|
|
72
|
+
if cost < best_cost then
|
|
73
|
+
best, best_cost = lines, cost
|
|
74
|
+
end
|
|
75
|
+
return
|
|
76
|
+
end
|
|
77
|
+
for j = i, n - kk + 1 do
|
|
78
|
+
local line = table.concat(words, " ", i, j)
|
|
79
|
+
local nxt = {}
|
|
80
|
+
for _, l in ipairs(cur) do
|
|
81
|
+
nxt[#nxt + 1] = l
|
|
82
|
+
end
|
|
83
|
+
nxt[#nxt + 1] = line
|
|
84
|
+
rec(
|
|
85
|
+
j + 1,
|
|
86
|
+
kk - 1,
|
|
87
|
+
nxt,
|
|
88
|
+
math.max(mx, #line),
|
|
89
|
+
single + (count_words(line) <= 1 and 1 or 0)
|
|
90
|
+
)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
rec(1, k, {}, 0, 0)
|
|
94
|
+
return best
|
|
95
|
+
end
|
|
96
|
+
local function mx_of(lines)
|
|
97
|
+
local m = 0
|
|
98
|
+
for _, l in ipairs(lines) do
|
|
99
|
+
m = math.max(m, #l)
|
|
100
|
+
end
|
|
101
|
+
return m
|
|
102
|
+
end
|
|
103
|
+
local function orphan(lines)
|
|
104
|
+
for _, l in ipairs(lines) do
|
|
105
|
+
if count_words(l) <= 1 then
|
|
106
|
+
return true
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
return false
|
|
110
|
+
end
|
|
111
|
+
local two = best_for(2)
|
|
112
|
+
if not orphan(two) and mx_of(two) <= 50 then
|
|
113
|
+
return two
|
|
114
|
+
end
|
|
115
|
+
return best_for(3)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
local function para(content, style)
|
|
119
|
+
return pandoc.Div(
|
|
120
|
+
{ pandoc.Para(content) },
|
|
121
|
+
pandoc.Attr("", {}, { ["custom-style"] = style })
|
|
122
|
+
)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
local function pagebreak()
|
|
126
|
+
return pandoc.RawBlock("openxml", '<w:p><w:r><w:br w:type="page"/></w:r></w:p>')
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
local function spacer(before)
|
|
130
|
+
return pandoc.RawBlock(
|
|
131
|
+
"openxml",
|
|
132
|
+
'<w:p><w:pPr><w:spacing w:before="' .. before .. '"/></w:pPr></w:p>'
|
|
133
|
+
)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
local function meta_str(meta, key)
|
|
137
|
+
local v = meta[key]
|
|
138
|
+
if v == nil then
|
|
139
|
+
return ""
|
|
140
|
+
end
|
|
141
|
+
return pandoc.utils.stringify(v)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
local function format_chapter_number(n)
|
|
145
|
+
if chapter_num_fmt == "arabic" then
|
|
146
|
+
return tostring(n)
|
|
147
|
+
else
|
|
148
|
+
return roman(n)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
local function Meta(meta)
|
|
153
|
+
if meta["heading_chapter_prefix"] ~= nil then
|
|
154
|
+
local pfx = meta_str(meta, "heading_chapter_prefix")
|
|
155
|
+
if pfx == "" then
|
|
156
|
+
chapter_prefix = ""
|
|
157
|
+
else
|
|
158
|
+
if not pfx:match("%s$") then
|
|
159
|
+
pfx = pfx .. " "
|
|
160
|
+
end
|
|
161
|
+
chapter_prefix = pfx
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
local fmt = meta_str(meta, "heading_chapter_num_format")
|
|
165
|
+
if fmt ~= "" then
|
|
166
|
+
chapter_num_fmt = fmt
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
function Header(el)
|
|
171
|
+
if FORMAT ~= "docx" then
|
|
172
|
+
return nil
|
|
173
|
+
end
|
|
174
|
+
local title = pandoc.utils.stringify(el.content)
|
|
175
|
+
if is_unnumbered(el) then
|
|
176
|
+
if el.level == 1 then
|
|
177
|
+
toc_entries[#toc_entries + 1] = {
|
|
178
|
+
level = 1,
|
|
179
|
+
id = el.identifier,
|
|
180
|
+
text = string.upper(title),
|
|
181
|
+
}
|
|
182
|
+
end
|
|
183
|
+
return nil
|
|
184
|
+
end
|
|
185
|
+
if el.level == 1 then
|
|
186
|
+
bab = bab + 1
|
|
187
|
+
sub = 0
|
|
188
|
+
subsub = 0
|
|
189
|
+
local bnum = format_chapter_number(bab)
|
|
190
|
+
local full_bab = chapter_prefix .. bnum
|
|
191
|
+
if chapter_prefix == "" then
|
|
192
|
+
full_bab = bnum .. "."
|
|
193
|
+
toc_entries[#toc_entries + 1] = {
|
|
194
|
+
level = 1,
|
|
195
|
+
id = el.identifier,
|
|
196
|
+
text = full_bab .. " " .. string.upper(title),
|
|
197
|
+
}
|
|
198
|
+
el.content = pandoc.List{
|
|
199
|
+
pandoc.Str(full_bab .. " " .. string.upper(title)),
|
|
200
|
+
}
|
|
201
|
+
else
|
|
202
|
+
toc_entries[#toc_entries + 1] = {
|
|
203
|
+
level = 1,
|
|
204
|
+
id = el.identifier,
|
|
205
|
+
text = full_bab .. " " .. string.upper(title),
|
|
206
|
+
}
|
|
207
|
+
el.content = pandoc.List{
|
|
208
|
+
pandoc.Str(full_bab),
|
|
209
|
+
pandoc.LineBreak(),
|
|
210
|
+
pandoc.Str(string.upper(title)),
|
|
211
|
+
}
|
|
212
|
+
end
|
|
213
|
+
elseif el.level == 2 then
|
|
214
|
+
sub = sub + 1
|
|
215
|
+
subsub = 0
|
|
216
|
+
toc_entries[#toc_entries + 1] = {
|
|
217
|
+
level = 2,
|
|
218
|
+
id = el.identifier,
|
|
219
|
+
text = bab .. "." .. sub .. ". " .. title,
|
|
220
|
+
}
|
|
221
|
+
el.content = pandoc.Str(bab .. "." .. sub .. ". " .. title)
|
|
222
|
+
elseif el.level == 3 then
|
|
223
|
+
subsub = subsub + 1
|
|
224
|
+
toc_entries[#toc_entries + 1] = {
|
|
225
|
+
level = 3,
|
|
226
|
+
id = el.identifier,
|
|
227
|
+
text = bab .. "." .. sub .. "." .. subsub .. " " .. title,
|
|
228
|
+
}
|
|
229
|
+
el.content = pandoc.Str(bab .. "." .. sub .. "." .. subsub .. " " .. title)
|
|
230
|
+
end
|
|
231
|
+
return el
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
local function toc_entry(e)
|
|
235
|
+
local style, ind, bold, spacing = "TOC1", 0, "<w:rPr><w:b/></w:rPr>", '<w:spacing w:before="120" w:after="40" w:line="260" w:lineRule="auto"/>'
|
|
236
|
+
if e.level == 2 then
|
|
237
|
+
style, ind, bold, spacing = "TOC2", 360, "", '<w:spacing w:before="20" w:after="20" w:line="240" w:lineRule="auto"/>'
|
|
238
|
+
elseif e.level == 3 then
|
|
239
|
+
style, ind, bold, spacing = "TOC3", 720, "", '<w:spacing w:before="0" w:after="0" w:line="240" w:lineRule="auto"/>'
|
|
240
|
+
end
|
|
241
|
+
return '<w:p><w:pPr><w:pStyle w:val="' .. style .. '"/>' ..
|
|
242
|
+
spacing ..
|
|
243
|
+
'<w:tabs><w:tab w:val="right" w:leader="dot" w:pos="9072"/></w:tabs>' ..
|
|
244
|
+
'<w:ind w:left="' .. ind .. '" w:right="0"/></w:pPr>' ..
|
|
245
|
+
'<w:hyperlink w:anchor="' .. e.id .. '" w:history="1">' ..
|
|
246
|
+
'<w:r>' .. bold .. '<w:t xml:space="preserve">' .. e.text .. '</w:t></w:r>' ..
|
|
247
|
+
'</w:hyperlink>' ..
|
|
248
|
+
'<w:r><w:tab/></w:r>' ..
|
|
249
|
+
'<w:r><w:fldChar w:fldCharType="begin" w:dirty="true"/></w:r>' ..
|
|
250
|
+
'<w:r><w:instrText xml:space="preserve"> PAGEREF ' .. e.id .. ' \\h </w:instrText></w:r>' ..
|
|
251
|
+
'<w:r><w:fldChar w:fldCharType="separate"/></w:r>' ..
|
|
252
|
+
'<w:r><w:t>0</w:t></w:r>' ..
|
|
253
|
+
'<w:r><w:fldChar w:fldCharType="end"/></w:r>' ..
|
|
254
|
+
'</w:p>'
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
local function daftar_isi()
|
|
258
|
+
local out = pandoc.List{}
|
|
259
|
+
out[#out + 1] = pagebreak()
|
|
260
|
+
out[#out + 1] = pandoc.RawBlock(
|
|
261
|
+
"openxml",
|
|
262
|
+
'<w:p><w:pPr><w:pStyle w:val="TOCHeading"/><w:jc w:val="center"/><w:outlineLvl w:val="9"/></w:pPr>' ..
|
|
263
|
+
'<w:r><w:rPr><w:b/><w:sz w:val="28"/><w:szCs w:val="28"/></w:rPr><w:t>DAFTAR ISI</w:t></w:r></w:p>'
|
|
264
|
+
)
|
|
265
|
+
out[#out + 1] = pandoc.RawBlock(
|
|
266
|
+
"openxml",
|
|
267
|
+
'<w:p><w:pPr><w:pStyle w:val="TOC1"/></w:pPr>' ..
|
|
268
|
+
'<w:r><w:fldChar w:fldCharType="begin" w:dirty="true"/></w:r>' ..
|
|
269
|
+
'<w:r><w:instrText xml:space="preserve"> TOC \\o "1-3" \\h \\z \\u </w:instrText></w:r>' ..
|
|
270
|
+
'<w:r><w:fldChar w:fldCharType="separate"/></w:r></w:p>'
|
|
271
|
+
)
|
|
272
|
+
for _, e in ipairs(toc_entries) do
|
|
273
|
+
out[#out + 1] = pandoc.RawBlock("openxml", toc_entry(e))
|
|
274
|
+
end
|
|
275
|
+
out[#out + 1] = pandoc.RawBlock(
|
|
276
|
+
"openxml",
|
|
277
|
+
'<w:p><w:pPr><w:pStyle w:val="TOC1"/></w:pPr>' ..
|
|
278
|
+
'<w:r><w:fldChar w:fldCharType="end"/></w:r></w:p>'
|
|
279
|
+
)
|
|
280
|
+
return out
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
function Pandoc(doc)
|
|
284
|
+
if FORMAT ~= "docx" then
|
|
285
|
+
return doc
|
|
286
|
+
end
|
|
287
|
+
local meta = doc.meta
|
|
288
|
+
local title = meta_str(meta, "title")
|
|
289
|
+
local subtitle = meta_str(meta, "subtitle")
|
|
290
|
+
local course = meta_str(meta, "course")
|
|
291
|
+
local lecturer = meta_str(meta, "lecturer")
|
|
292
|
+
local faculty = meta_str(meta, "faculty")
|
|
293
|
+
local institution = meta_str(meta, "institution")
|
|
294
|
+
local year = meta_str(meta, "year")
|
|
295
|
+
|
|
296
|
+
local blocks = pandoc.List{}
|
|
297
|
+
|
|
298
|
+
if title ~= "" then
|
|
299
|
+
local tlines = balance_title(string.upper(title))
|
|
300
|
+
local content = {}
|
|
301
|
+
for i, l in ipairs(tlines) do
|
|
302
|
+
if i > 1 then
|
|
303
|
+
content[#content + 1] = pandoc.LineBreak()
|
|
304
|
+
end
|
|
305
|
+
content[#content + 1] = pandoc.Str(l)
|
|
306
|
+
end
|
|
307
|
+
blocks[#blocks + 1] = para(content, "CoverTitle")
|
|
308
|
+
if subtitle ~= "" then
|
|
309
|
+
blocks[#blocks + 1] = para({ pandoc.Str(string.upper(subtitle)) }, "CoverSubtitle")
|
|
310
|
+
end
|
|
311
|
+
if course ~= "" then
|
|
312
|
+
blocks[#blocks + 1] = para({ pandoc.Strong(pandoc.Str(course)) }, "CoverCourse")
|
|
313
|
+
end
|
|
314
|
+
local hide_lecturer = meta_str(meta, "cover_hide_lecturer") == "true" or meta_str(meta, "cover_show_lecturer") == "false"
|
|
315
|
+
if lecturer ~= "" and not hide_lecturer then
|
|
316
|
+
local lecturer_lbl = meta_str(meta, "lecturer_label")
|
|
317
|
+
if lecturer_lbl == "" then
|
|
318
|
+
lecturer_lbl = "Dosen Pengampu: "
|
|
319
|
+
else
|
|
320
|
+
if not lecturer_lbl:match(":%s*$") then
|
|
321
|
+
lecturer_lbl = lecturer_lbl .. ": "
|
|
322
|
+
elseif not lecturer_lbl:match("%s$") then
|
|
323
|
+
lecturer_lbl = lecturer_lbl .. " "
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
blocks[#blocks + 1] = para(
|
|
327
|
+
{ pandoc.Str(lecturer_lbl), pandoc.Strong(pandoc.Str(lecturer)) },
|
|
328
|
+
"CoverLecturer"
|
|
329
|
+
)
|
|
330
|
+
end
|
|
331
|
+
local logo_width = meta_str(meta, "cover_logo_width")
|
|
332
|
+
if logo_width == "" then
|
|
333
|
+
logo_width = "4cm"
|
|
334
|
+
end
|
|
335
|
+
blocks[#blocks + 1] = spacer(640)
|
|
336
|
+
blocks[#blocks + 1] = pandoc.Div(
|
|
337
|
+
{ pandoc.Para({ pandoc.Image({}, "logo.jpg", "", pandoc.Attr("", {}, { width = logo_width })) }) },
|
|
338
|
+
pandoc.Attr("", {}, { ["custom-style"] = "CoverImage" })
|
|
339
|
+
)
|
|
340
|
+
blocks[#blocks + 1] = spacer(640)
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
local authors = meta["author"]
|
|
344
|
+
if authors ~= nil then
|
|
345
|
+
local author_list = {}
|
|
346
|
+
if authors[1] ~= nil then
|
|
347
|
+
for _, a in ipairs(authors) do
|
|
348
|
+
author_list[#author_list + 1] = a
|
|
349
|
+
end
|
|
350
|
+
else
|
|
351
|
+
author_list[#author_list + 1] = authors
|
|
352
|
+
end
|
|
353
|
+
if #author_list > 0 then
|
|
354
|
+
blocks[#blocks + 1] = para({ pandoc.Str("Disusun oleh:") }, "CoverLine")
|
|
355
|
+
for _, a in ipairs(author_list) do
|
|
356
|
+
local name = pandoc.utils.stringify(a["name"] or a)
|
|
357
|
+
local nim = pandoc.utils.stringify(a["nim"] or "")
|
|
358
|
+
blocks[#blocks + 1] = para({ pandoc.Strong(pandoc.Str(name)) }, "CoverName")
|
|
359
|
+
if nim ~= "" then
|
|
360
|
+
blocks[#blocks + 1] = para({ pandoc.Str(nim) }, "CoverLine")
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
if faculty ~= "" or institution ~= "" or year ~= "" then
|
|
367
|
+
blocks[#blocks + 1] = spacer(640)
|
|
368
|
+
if faculty ~= "" then
|
|
369
|
+
blocks[#blocks + 1] = para({ pandoc.Str(string.upper(faculty)) }, "CoverInstitution")
|
|
370
|
+
end
|
|
371
|
+
if institution ~= "" then
|
|
372
|
+
blocks[#blocks + 1] = para({ pandoc.Str(string.upper(institution)) }, "CoverInstitution")
|
|
373
|
+
end
|
|
374
|
+
if year ~= "" then
|
|
375
|
+
blocks[#blocks + 1] = para({ pandoc.Str(string.upper(year)) }, "CoverInstitution")
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
-- Section break (Next Page) penutup cover: tanpa footer/nomor halaman
|
|
380
|
+
blocks[#blocks + 1] = pandoc.RawBlock(
|
|
381
|
+
"openxml",
|
|
382
|
+
'<w:p><w:pPr><w:sectPr><w:footnotePr><w:numRestart w:val="eachSect"/></w:footnotePr><w:pgSz w:w="11906" w:h="16838"/><w:pgMar w:top="1134" w:right="1417" w:bottom="1701" w:left="1417" w:header="720" w:footer="720" w:gutter="0"/></w:sectPr></w:pPr></w:p>'
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
meta.title = nil
|
|
386
|
+
meta.subtitle = nil
|
|
387
|
+
meta.date = nil
|
|
388
|
+
meta.author = nil
|
|
389
|
+
meta.abstract = nil
|
|
390
|
+
meta["abstract-title"] = nil
|
|
391
|
+
|
|
392
|
+
local body = pandoc.List{}
|
|
393
|
+
local inserted = false
|
|
394
|
+
for _, blk in ipairs(doc.blocks) do
|
|
395
|
+
if
|
|
396
|
+
not inserted
|
|
397
|
+
and blk.tag == "Header"
|
|
398
|
+
and blk.level == 1
|
|
399
|
+
and not is_unnumbered(blk)
|
|
400
|
+
then
|
|
401
|
+
for _, b in ipairs(daftar_isi()) do
|
|
402
|
+
body[#body + 1] = b
|
|
403
|
+
end
|
|
404
|
+
inserted = true
|
|
405
|
+
end
|
|
406
|
+
body[#body + 1] = blk
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
doc.blocks = blocks .. body
|
|
410
|
+
return doc
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
return {
|
|
414
|
+
{ Meta = Meta },
|
|
415
|
+
{ Header = Header, Pandoc = Pandoc }
|
|
416
|
+
}
|