简体   繁体   English

如何在 Bookdown 的目录中添加任意元素?

[英]How can I add arbitrary elements to the Table of Contents in Bookdown?

I am making a book via bookdown .我正在通过bookdown制作一本书。 I know it is possible to omit headings from the Table of Contents by adding the attributes {.unlisted.unnumbered} , as shown inSection 4.18 of the R Markdown Cookbook .我知道可以通过添加属性{.unlisted.unnumbered}从目录中省略标题,如R Markdown Cookbook 的第 4.18 节所示。 However, how can I add arbitrary content to the Table of Contents?但是,如何将任意内容添加到目录中? If I only needed to add this for the PDF output, I could use (eg) the LaTeX command \addcontentsline , but I need this to show in the HTML contents sidebar as well. If I only needed to add this for the PDF output, I could use (eg) the LaTeX command \addcontentsline , but I need this to show in the HTML contents sidebar as well.

For example, if you set up a new default bookdown project from RStudio, it includes the file 01-intro.Rmd .例如,如果您从 RStudio 设置一个新的默认bookdown项目,它包含文件01-intro.Rmd The first few lines are前几行是

# 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.

I need to be able to create arbitrary div s that are added to the table of contents, like so:我需要能够创建添加到目录中的任意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.
:::

Which would add the sentence "Figures and tables with captions will be placed in figure and table environments, respectively."这将添加句子“带有标题的图形和表格将分别放置在figuretable环境中”。 in both the LaTeX Table of Contents and the sidebar on the HTML output.在 LaTeX 目录和 HTML output 的侧边栏中。 The context of this problem is that I need to place a header inside another custom div that formats the content within a colorbox to make it stand out.这个问题的背景是我需要将 header 放在另一个自定义div中,该 div 对颜色框中的内容进行格式化以使其脱颖而出。 Otherwise, I could of course just add another heading via ## before the sentence above.否则,我当然可以在上面的句子之前通过##添加另一个标题。

Maybe this solution?也许这个解决方案?

CSS-file: 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-file: 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?

在此处输入图像描述

We'll be using a Lua filter for this, as those are a good way to modify R Markdown behavior.我们将为此使用Lua 过滤器,因为这是修改 R Markdown 行为的好方法。 The "Bookdown Cookbook" has an excellent overview and includes a description of how to use Lua filters. “Bookdown Cookbook”有一个 很好的概述,包括如何使用 Lua 滤波器的描述。

The way we are doing this is to side-step the normal TOC generator and rewrite it in Lua.我们这样做的方法是绕过普通的 TOC 生成器,并在 Lua 中重写它。 Then we add our new TOC as a meta value named table-of-contents (and toc , for compatibility), which is enough to be included in the output.然后我们将新的 TOC 添加为一个名为table-of-contents的元值(和toc ,以实现兼容性),这足以包含在 output 中。

So first let's dump the code to create a normal TOC:所以首先让我们转储代码来创建一个普通的 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
  },
}

The code makes a few minor simplifications, but should produce an identical TOC for most documents.该代码进行了一些小的简化,但应该为大多数文档生成相同的 TOC。 Now we can go on and modify the code to our liking.现在我们可以打开 go 并根据自己的喜好修改代码。 For example, to include divs with the class toc-line , the section_to_toc_item could be modified by adding this code at the start of the function:例如,要包含带有 class toc-line的 div,可以通过在 function 的开头添加以下代码来修改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

Modify the code as you see fit.修改您认为合适的代码。

Also, if you want to exclude the extra TOC lines from the normal output, you'll have to filter them out.此外,如果您想从正常的 output 中排除额外的 TOC 行,则必须将它们过滤掉。 Let the script return a second filter to do that:让脚本返回第二个过滤器来执行此操作:

return {
  { Pandoc = function (doc) ... end },
  { Div = function (div) return div.classes:includes 'toc-line' and {} or nil end }
}

We could use an R function that prints a colored box and adds the title to the TOC depending on the output format .我们可以使用 R function 打印一个彩色框并将标题添加到 TOC ,具体取决于 output 格式 For gitbook output, this is easily done using HTML and markdown.对于gitbook output,这很容易使用 HTML 和 markdown 完成。 For pdf_book we may use a LaTeX environment for colored boxes like tcolorbox .对于pdf_book ,我们可以使用 LaTeX 环境来处理像tcolorbox这样的彩色盒子。

Here is the function (define in a code block in.Rmd file):这是function(在.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 = "")
  }
}

Depending on the output format, block_toc() concatenates and prints the code for the blocks and, of course, also ensures that the title is added to the TOC.根据 output 格式, block_toc()连接并打印块的代码,当然,还确保将标题添加到 TOC。 You can set the level of the TOC where the box title is added using level .您可以使用 level 设置添加框标题的 TOC 的level

Use block_toc() like this in a chunk:在一个块中使用这样的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") will get and pass the current output format to the function when building the book. output = knitr::opts_knit$get("rmarkdown.pandoc.to")将获取当前的 output 格式并将其传递给 ZC1C425268E68385D1AB5074C17A9F 构建时的 ZC1C425268E68385D1AB5074C17A9F4 格式


Some styles for appealing boxes部分 styles 用于上诉箱

Add to preamble.tex (for colored box in PDF output -- include file in YAML header).添加到preamble.tex (对于 PDF output 中的彩色框 - 在 YAML 标头中包含文件)。 This will define a tcolorbox environment for generating blue boxes.这将定义一个用于生成蓝色框的tcolorbox环境。

\usepackage{tcolorbox}
\definecolor{blue}{HTML}{D7DDEF}
\definecolor{darkblue}{HTML}{2B4E70}
\newtcolorbox{mybox}{colback=blue, colframe=darkblue}

Add to style.css (styles for HTML colored box) or include in a ```{css} code chunk:添加到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;
}

For HTML output ( gitbook ) this yields对于 HTML output ( gitbook ) 这会产生

在此处输入图像描述

and for LaTeX output ( pdf_book ) it looks like this对于 LaTeX output ( pdf_book ) 它看起来像这样

在此处输入图像描述

with a corresponding entry at the section level in the TOC.在 TOC 的章节级别有相应的条目。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM