如何将任意元素添加到 Bookdown 中目录的 Table?
How can I add arbitrary elements to the Table of Contents in Bookdown?
我正在通过 bookdown
制作一本书。
我知道可以通过添加属性 {.unlisted .unnumbered}
来省略目录 Table 中的标题,如 Section 4.18 of the R Markdown Cookbook 所示。
但是,如何将任意内容添加到目录的 Table 中?
如果我只需要为 PDF 输出添加它,我可以使用(例如)LaTeX 命令 \addcontentsline
,但我还需要它显示在 HTML 内容侧栏中。
例如,如果您从 RStudio 设置一个新的默认 bookdown
项目,它包含文件 01-intro.Rmd
。
前几行是
# Introduction {#intro}
You can label chapter and section titles using `{#label}` after them, e.g., we can reference Chapter \@ref(intro). If you do not manually label them, there will be automatic labels anyway, e.g., Chapter \@ref(methods).
Figures and tables with captions will be placed in `figure` and `table` environments, respectively.
我需要能够创建添加到 table 内容的任意 div
,如下所示:
# Introduction {#intro}
You can label chapter and section titles using `{#label}` after them, e.g., we can reference Chapter \@ref(intro). If you do not manually label them, there will be automatic labels anyway, e.g., Chapter \@ref(methods).
::: {#arbitrary-header <some other attribute?>}
Figures and tables with captions will be placed in `figure` and `table` environments, respectively.
:::
这将添加句子“Figures and tables with captions will be placed in respectively in figure
and table
environments.”在目录的 LaTeX Table 和 HTML 输出的侧边栏中。
这个问题的上下文是我需要在另一个自定义 div
中放置一个 header,该自定义 div
对颜色框内的内容进行格式化以使其脱颖而出。
否则,我当然可以在上面的句子之前通过 ##
添加另一个标题。
也许是这个解决方案?
CSS-文件:
k1 {
font-family: 'Times New Roman', Times, serif;
font-size: 12pt;
text-align: justify;
}
#TOC {
color:black;
background-color: white;
position: fixed;
top: 0;
left: 0;
width: 250px;
padding: 10px;
overflow:auto;
margin-left: -5px;
}
body {
max-width: 800px;
margin-left:300px;
line-height: 20px;
}
div#TOC li {
list-style:none;
}
h2#toc-title {
font-size: 24px;
color: Red;
}
Rmd-文件:
---
title: "Arbitrary elements"
author: "Me"
date: "`r Sys.Date()`"
output:
bookdown::html_document2:
toc: true
css: "arb.css"
toc-title: "Contents"
---
# My question is it: "..."
# Introduction of our story ...
# It was a strange person ...
## The Flame was in his body ...
# <k1> Figures and tables with captions will be placed in `figure` and `table` environments, respectively. </k1> {-}
## Where is the love, friends?
我们将使用 Lua filter for this, as those are a good way to modify R Markdown behavior. The "Bookdown Cookbook" has an excellent overview 并包含如何使用 Lua 过滤器的说明。
我们这样做的方法是避开正常的 TOC 生成器并在 Lua 中重写它。然后我们将新的 TOC 添加为名为 table-of-contents
(和 toc
以实现兼容性)的元值,这足以包含在输出中。
所以首先让我们转储代码来创建一个普通目录:
_ENV = pandoc
local not_empty = function (x) return #x > 0 end
local section_to_toc_item
local function to_toc_item (number, text, id, subcontents)
if number then
text = Span({Str(number),Space()} .. text, {class='toc-section-number'})
end
local header_link = id == '' and text or Link(text, '#' .. id)
local subitems = subcontents:map(section_to_toc_item):filter(not_empty)
return List{Plain{header_link}} ..
(#subitems == 0 and {} or {BulletList(subitems)})
end
section_to_toc_item = function (div)
-- bail if this is not a section wrapper
if div.t ~= 'Div' or not div.content[1] or div.content[1].t ~= 'Header' then
return {}
end
local heading = div.content:remove(1)
local number = heading.attributes.number
-- bail if this is not supposed to be included in the toc
if not number and heading.classes:includes 'unlisted' then
return {}
end
return to_toc_item(number, heading.content, div.identifier, div.content)
end
-- return filter
return {
{ Pandoc = function (doc)
local sections = utils.make_sections(true, nil, doc.blocks)
local toc_items = sections:map(section_to_toc_item):filter(not_empty)
doc.meta['table-of-contents'] = {BulletList(toc_items)}
doc.meta.toc = doc.meta['table-of-contents']
return doc
end
},
}
代码进行了一些小的简化,但应该为大多数文档生成相同的目录。现在我们可以继续并根据自己的喜好修改代码。例如,要包含带有 class toc-line
的 div,可以通过在函数开头添加以下代码来修改 section_to_toc_item
:
section_to_toc_item = function (div)
if div.t == 'Div' and div.classes:includes('toc-line') then
return to_toc_item(nil, utils.blocks_to_inlines(div.content), div.identifier)
end
⋮
end
根据需要修改代码。
此外,如果您想从正常输出中排除额外的 TOC 行,则必须将它们过滤掉。让脚本 return 第二个过滤器来执行此操作:
return {
{ Pandoc = function (doc) ... end },
{ Div = function (div) return div.classes:includes 'toc-line' and {} or nil end }
}
我们可以使用 R 函数打印彩色框并将标题添加到 TOC 取决于输出格式。对于 gitbook
输出,这很容易使用 HTML 和降价来完成。对于 pdf_book
我们可以使用 LaTeX 环境来处理像 tcolorbox.
这样的彩色框
这是函数(在 .Rmd 文件的代码块中定义):
block_toc <- function(title, level, content, output) {
if(output == "html") {
title <- paste(paste(rep("#", level), collapse = ""), title, "{-}")
cat('<div class = "myblock">', title, '<p>', content, '</p>\n</div>', sep = "\n")
} else {
level <- c("part", "chapter", "section")[level]
cat('\addcontentsline{toc}{', level, '}{', title, '}',
'\n\begin{mybox}\n\textbf{\noindent ', title, '}\n\medskip\n\n', content,
'\n\n\end{mybox}', sep = "")
}
}
根据输出格式,block_toc()
连接并打印块的代码,当然,还确保将标题添加到目录中。您可以使用 level
.
设置添加框标题的 TOC 级别
在块中像这样使用 block_toc()
:
```{r, results='asis', echo=F, eval=T}
block_toc(
title = "Central Limit Theorem",
level = 2
content = "The CLT states that, as $n$ goes to infinity,
the sample average $\bar{X}$ converges in distribution
to $\mathcal{N}(\mu,\sigma^2/n)$.",
output = knitr::opts_knit$get("rmarkdown.pandoc.to")
)
```
output = knitr::opts_knit$get("rmarkdown.pandoc.to")
会在建书时获取当前输出格式并将其传递给函数
吸引人的盒子的一些样式
添加到 preamble.tex(对于 PDF 输出中的彩色框 - 在 YAML header 中包含文件)。这将为生成蓝框定义一个 tcolorbox
环境。
\usepackage{tcolorbox}
\definecolor{blue}{HTML}{D7DDEF}
\definecolor{darkblue}{HTML}{2B4E70}
\newtcolorbox{mybox}{colback=blue, colframe=darkblue}
添加到 style.css(HTML 彩色框的样式)或包含在 ```{css}
代码块中:
.myblock {
background-color: #d7ddef;
border: solid #2b4e70;
border-radius: 15px;
}
.myblock p, .myblock h2, .myblock h3 {
padding: 5px 5px 5px 20px;
margin-top: 0px !important;
}
对于 HTML 输出 (gitbook
) 这会产生
对于 LaTeX 输出 (pdf_book
) 它看起来像这样
在 TOC 的章节级别有相应的条目。
我正在通过 bookdown
制作一本书。
我知道可以通过添加属性 {.unlisted .unnumbered}
来省略目录 Table 中的标题,如 Section 4.18 of the R Markdown Cookbook 所示。
但是,如何将任意内容添加到目录的 Table 中?
如果我只需要为 PDF 输出添加它,我可以使用(例如)LaTeX 命令 \addcontentsline
,但我还需要它显示在 HTML 内容侧栏中。
例如,如果您从 RStudio 设置一个新的默认 bookdown
项目,它包含文件 01-intro.Rmd
。
前几行是
# Introduction {#intro}
You can label chapter and section titles using `{#label}` after them, e.g., we can reference Chapter \@ref(intro). If you do not manually label them, there will be automatic labels anyway, e.g., Chapter \@ref(methods).
Figures and tables with captions will be placed in `figure` and `table` environments, respectively.
我需要能够创建添加到 table 内容的任意 div
,如下所示:
# Introduction {#intro}
You can label chapter and section titles using `{#label}` after them, e.g., we can reference Chapter \@ref(intro). If you do not manually label them, there will be automatic labels anyway, e.g., Chapter \@ref(methods).
::: {#arbitrary-header <some other attribute?>}
Figures and tables with captions will be placed in `figure` and `table` environments, respectively.
:::
这将添加句子“Figures and tables with captions will be placed in respectively in figure
and table
environments.”在目录的 LaTeX Table 和 HTML 输出的侧边栏中。
这个问题的上下文是我需要在另一个自定义 div
中放置一个 header,该自定义 div
对颜色框内的内容进行格式化以使其脱颖而出。
否则,我当然可以在上面的句子之前通过 ##
添加另一个标题。
也许是这个解决方案?
CSS-文件:
k1 {
font-family: 'Times New Roman', Times, serif;
font-size: 12pt;
text-align: justify;
}
#TOC {
color:black;
background-color: white;
position: fixed;
top: 0;
left: 0;
width: 250px;
padding: 10px;
overflow:auto;
margin-left: -5px;
}
body {
max-width: 800px;
margin-left:300px;
line-height: 20px;
}
div#TOC li {
list-style:none;
}
h2#toc-title {
font-size: 24px;
color: Red;
}
Rmd-文件:
---
title: "Arbitrary elements"
author: "Me"
date: "`r Sys.Date()`"
output:
bookdown::html_document2:
toc: true
css: "arb.css"
toc-title: "Contents"
---
# My question is it: "..."
# Introduction of our story ...
# It was a strange person ...
## The Flame was in his body ...
# <k1> Figures and tables with captions will be placed in `figure` and `table` environments, respectively. </k1> {-}
## Where is the love, friends?
我们将使用 Lua filter for this, as those are a good way to modify R Markdown behavior. The "Bookdown Cookbook" has an excellent overview 并包含如何使用 Lua 过滤器的说明。
我们这样做的方法是避开正常的 TOC 生成器并在 Lua 中重写它。然后我们将新的 TOC 添加为名为 table-of-contents
(和 toc
以实现兼容性)的元值,这足以包含在输出中。
所以首先让我们转储代码来创建一个普通目录:
_ENV = pandoc
local not_empty = function (x) return #x > 0 end
local section_to_toc_item
local function to_toc_item (number, text, id, subcontents)
if number then
text = Span({Str(number),Space()} .. text, {class='toc-section-number'})
end
local header_link = id == '' and text or Link(text, '#' .. id)
local subitems = subcontents:map(section_to_toc_item):filter(not_empty)
return List{Plain{header_link}} ..
(#subitems == 0 and {} or {BulletList(subitems)})
end
section_to_toc_item = function (div)
-- bail if this is not a section wrapper
if div.t ~= 'Div' or not div.content[1] or div.content[1].t ~= 'Header' then
return {}
end
local heading = div.content:remove(1)
local number = heading.attributes.number
-- bail if this is not supposed to be included in the toc
if not number and heading.classes:includes 'unlisted' then
return {}
end
return to_toc_item(number, heading.content, div.identifier, div.content)
end
-- return filter
return {
{ Pandoc = function (doc)
local sections = utils.make_sections(true, nil, doc.blocks)
local toc_items = sections:map(section_to_toc_item):filter(not_empty)
doc.meta['table-of-contents'] = {BulletList(toc_items)}
doc.meta.toc = doc.meta['table-of-contents']
return doc
end
},
}
代码进行了一些小的简化,但应该为大多数文档生成相同的目录。现在我们可以继续并根据自己的喜好修改代码。例如,要包含带有 class toc-line
的 div,可以通过在函数开头添加以下代码来修改 section_to_toc_item
:
section_to_toc_item = function (div)
if div.t == 'Div' and div.classes:includes('toc-line') then
return to_toc_item(nil, utils.blocks_to_inlines(div.content), div.identifier)
end
⋮
end
根据需要修改代码。
此外,如果您想从正常输出中排除额外的 TOC 行,则必须将它们过滤掉。让脚本 return 第二个过滤器来执行此操作:
return {
{ Pandoc = function (doc) ... end },
{ Div = function (div) return div.classes:includes 'toc-line' and {} or nil end }
}
我们可以使用 R 函数打印彩色框并将标题添加到 TOC 取决于输出格式。对于 gitbook
输出,这很容易使用 HTML 和降价来完成。对于 pdf_book
我们可以使用 LaTeX 环境来处理像 tcolorbox.
这是函数(在 .Rmd 文件的代码块中定义):
block_toc <- function(title, level, content, output) {
if(output == "html") {
title <- paste(paste(rep("#", level), collapse = ""), title, "{-}")
cat('<div class = "myblock">', title, '<p>', content, '</p>\n</div>', sep = "\n")
} else {
level <- c("part", "chapter", "section")[level]
cat('\addcontentsline{toc}{', level, '}{', title, '}',
'\n\begin{mybox}\n\textbf{\noindent ', title, '}\n\medskip\n\n', content,
'\n\n\end{mybox}', sep = "")
}
}
根据输出格式,block_toc()
连接并打印块的代码,当然,还确保将标题添加到目录中。您可以使用 level
.
在块中像这样使用 block_toc()
:
```{r, results='asis', echo=F, eval=T}
block_toc(
title = "Central Limit Theorem",
level = 2
content = "The CLT states that, as $n$ goes to infinity,
the sample average $\bar{X}$ converges in distribution
to $\mathcal{N}(\mu,\sigma^2/n)$.",
output = knitr::opts_knit$get("rmarkdown.pandoc.to")
)
```
output = knitr::opts_knit$get("rmarkdown.pandoc.to")
会在建书时获取当前输出格式并将其传递给函数
吸引人的盒子的一些样式
添加到 preamble.tex(对于 PDF 输出中的彩色框 - 在 YAML header 中包含文件)。这将为生成蓝框定义一个 tcolorbox
环境。
\usepackage{tcolorbox}
\definecolor{blue}{HTML}{D7DDEF}
\definecolor{darkblue}{HTML}{2B4E70}
\newtcolorbox{mybox}{colback=blue, colframe=darkblue}
添加到 style.css(HTML 彩色框的样式)或包含在 ```{css}
代码块中:
.myblock {
background-color: #d7ddef;
border: solid #2b4e70;
border-radius: 15px;
}
.myblock p, .myblock h2, .myblock h3 {
padding: 5px 5px 5px 20px;
margin-top: 0px !important;
}
对于 HTML 输出 (gitbook
) 这会产生
对于 LaTeX 输出 (pdf_book
) 它看起来像这样
在 TOC 的章节级别有相应的条目。