【问题标题】:Code folding in bookdownbookdown 中的代码折叠
【发布时间】:2017-07-27 21:05:24
【问题描述】:

RMarkdown 中用于 html 文档的代码折叠选项非常棒。该选项使编程方法对感兴趣的人透明,而不会强迫观众滚动数英里的代码。代码与散文和交互式图形输出的紧密放置使整个项目更容易被更广泛的受众访问,而且它减少了对额外文档的需求。

对于一个较大的项目,我使用的是 bookdown,效果很好。唯一的问题是没有代码折叠选项。 bookdown 中当前未启用代码折叠。 (见Enable code folding in bookdown

我知道我不需要任何选项来实现它。我只需要将正确的代码粘贴到正确的位置。但是什么代码和在哪里?

一个可行的替代方法是将代码块放在页面中块的输出下方。或者,最后,将它们作为附录。我可以用 html 做到这一点,但不能像 rbookdown 那样重现。

【问题讨论】:

标签: javascript html r code-folding bookdown


【解决方案1】:

整个页面的全局隐藏/显示按钮

要使用@Yihui 的提示折叠所有html 输出中的代码的按钮,您需要将以下代码粘贴到外部文件中(我在这里将其命名为header.html):

编辑:我修改了函数toggle_R,使按钮在点击时显示Hide GlobalShow Global

<script type="text/javascript">

// toggle visibility of R source blocks in R Markdown output
function toggle_R() {
  var x = document.getElementsByClassName('r');
  if (x.length == 0) return;
  function toggle_vis(o) {
    var d = o.style.display;
    o.style.display = (d == 'block' || d == '') ? 'none':'block';
  }

  for (i = 0; i < x.length; i++) {
    var y = x[i];
    if (y.tagName.toLowerCase() === 'pre') toggle_vis(y);
  }

    var elem = document.getElementById("myButton1");
    if (elem.value === "Hide Global") elem.value = "Show Global";
    else elem.value = "Hide Global";
}

document.write('<input onclick="toggle_R();" type="button" value="Hide Global" id="myButton1" style="position: absolute; top: 10%; right: 2%; z-index: 200"></input>')

</script>

在此脚本中,您可以直接使用 style 选项修改与按钮关联的位置和 css 代码,或将其添加到您的 css 文件中。我必须将 z-index 设置为较高的值,以确保它出现在其他部门之上。
请注意,此 javascript 代码仅折叠使用 echo=TRUE 调用的 R 代码,该代码在 html 中归因于 class="r"。这是由命令var x = document.getElementsByClassName('r'); 定义的

然后,您在 rmarkdown 脚本的 YAML 标头中调用此文件,如下例所示:

---
title: "Toggle R code"
author: "StatnMap"
date: '`r format(Sys.time(), "%d %B, %Y")`'
output:
  bookdown::html_document2:
    includes:
      in_header: header.html
  bookdown::gitbook:
    includes:
      in_header: header.html
---

Stackoverflow question
<https://stackoverflow.com/questions/45360998/code-folding-in-bookdown>

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

## R Markdown

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see <http://rmarkdown.rstudio.com>.

When you click the **Knit** button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:

```{r cars}
summary(cars)
```

新编辑:每个区块的本地隐藏/显示按钮

我终于找到了解决办法!
在查看正常 html 输出(无 bookdown)的代码折叠行为时,我能够将其添加到 bookdown。主要的 javascript 函数需要找到 .sourceCode 类划分才能使用 bookdown。但是,这也需要 bootstrap 的补充 javascript 函数,但不是全部。这适用于gitbookhtml_document2
步骤如下:

  1. 在与您的 Rmd 文件相同的目录中创建一个 js 文件夹
  2. 在此处下载 javascript 函数 transition.jscollapse.js 例如:https://github.com/twbs/bootstrap/tree/v3.3.7/js 并将它们存储在您的 js 文件夹中
  3. js 文件夹中创建一个名为codefolding.js 的新文件,代码如下。这与 rmarkdown code_folding 选项相同,但添加了 pre.sourceCode 以查找 R 代码块:

codefolding.js代码:

window.initializeCodeFolding = function(show) {

  // handlers for show-all and hide all
  $("#rmd-show-all-code").click(function() {
    $('div.r-code-collapse').each(function() {
      $(this).collapse('show');
    });
  });
  $("#rmd-hide-all-code").click(function() {
    $('div.r-code-collapse').each(function() {
      $(this).collapse('hide');
    });
  });

  // index for unique code element ids
  var currentIndex = 1;

  // select all R code blocks
  var rCodeBlocks = $('pre.sourceCode, pre.r, pre.python, pre.bash, pre.sql, pre.cpp, pre.stan');
  rCodeBlocks.each(function() {

    // create a collapsable div to wrap the code in
    var div = $('<div class="collapse r-code-collapse"></div>');
    if (show)
      div.addClass('in');
    var id = 'rcode-643E0F36' + currentIndex++;
    div.attr('id', id);
    $(this).before(div);
    $(this).detach().appendTo(div);

    // add a show code button right above
    var showCodeText = $('<span>' + (show ? 'Hide' : 'Code') + '</span>');
    var showCodeButton = $('<button type="button" class="btn btn-default btn-xs code-folding-btn pull-right"></button>');
    showCodeButton.append(showCodeText);
    showCodeButton
        .attr('data-toggle', 'collapse')
        .attr('data-target', '#' + id)
        .attr('aria-expanded', show)
        .attr('aria-controls', id);

    var buttonRow = $('<div class="row"></div>');
    var buttonCol = $('<div class="col-md-12"></div>');

    buttonCol.append(showCodeButton);
    buttonRow.append(buttonCol);

    div.before(buttonRow);

    // update state of button on show/hide
    div.on('hidden.bs.collapse', function () {
      showCodeText.text('Code');
    });
    div.on('show.bs.collapse', function () {
      showCodeText.text('Hide');
    });
  });

}
  1. 在以下 rmarkdown 脚本中,所有三个函数都按原样读取并包含在标题中,因此 js 文件夹对最终文档本身没有用处。在阅读js函数的时候,我还默认添加了show代码块的选项,但是你可以选择用hide隐藏它们。

降价代码:

---
title: "Toggle R code"
author: "StatnMap"
date: '`r format(Sys.time(), "%d %B, %Y")`'
output:
  bookdown::html_document2:
    includes:
      in_header: header.html
  bookdown::gitbook:
    includes:
      in_header: header.html
---

Stackoverflow question
<https://stackoverflow.com/questions/45360998/code-folding-in-bookdown>


```{r setup, include=FALSE}
# Add a common class name for every chunks
knitr::opts_chunk$set(
  echo = TRUE)
```
```{r htmlTemp3, echo=FALSE, eval=TRUE}
codejs <- readr::read_lines("js/codefolding.js")
collapsejs <- readr::read_lines("js/collapse.js")
transitionjs <- readr::read_lines("js/transition.js")

htmlhead <- 
  paste('
<script>',
paste(transitionjs, collapse = "\n"),
'</script>
<script>',
paste(collapsejs, collapse = "\n"),
'</script>
<script>',
paste(codejs, collapse = "\n"),
'</script>
<style type="text/css">
.code-folding-btn { margin-bottom: 4px; }
.row { display: flex; }
.collapse { display: none; }
.in { display:block }
</style>
<script>
$(document).ready(function () {
  window.initializeCodeFolding("show" === "show");
});
</script>
', sep = "\n")

readr::write_lines(htmlhead, path = "header.html")
```

## R Markdown

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see <http://rmarkdown.rstudio.com>.

When you click the **Knit** button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:

```{r cars}
summary(cars)
```

```{r plot}
plot(cars)
```

此脚本在 Rstudio 浏览器中显示按钮,但效果不佳。但是,这对 Firefox 来说没问题。
你会看到这段代码中有一点css,当然你可以用更多的css来修改这些按钮的位置和颜色以及任何你想要的东西。

编辑:结合全局和本地按钮

编辑 2017-11-13:全局代码折叠按钮与单个块按钮很好地集成。 函数 toggle_R 最终不是必需的,但您需要在引导程序中获取函数 dropdown.js

调用js文件时直接在代码块中调用全局按钮:

```{r htmlTemp3, echo=FALSE, eval=TRUE}
codejs <- readr::read_lines("/mnt/Data/autoentrepreneur/js/codefolding.js")
collapsejs <- readr::read_lines("/mnt/Data/autoentrepreneur/js/collapse.js")
transitionjs <- readr::read_lines("/mnt/Data/autoentrepreneur/js/transition.js")
dropdownjs <- readr::read_lines("/mnt/Data/autoentrepreneur/js/dropdown.js")

htmlhead <- c(
  paste('
<script>',
paste(transitionjs, collapse = "\n"),
'</script>
<script>',
paste(collapsejs, collapse = "\n"),
'</script>
<script>',
paste(codejs, collapse = "\n"),
'</script>
<script>',
paste(dropdownjs, collapse = "\n"),
'</script>
<style type="text/css">
.code-folding-btn { margin-bottom: 4px; }
.row { display: flex; }
.collapse { display: none; }
.in { display:block }
.pull-right > .dropdown-menu {
    right: 0;
    left: auto;
}
.open > .dropdown-menu {
    display: block;
}
.dropdown-menu {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 1000;
    display: none;
    float: left;
    min-width: 160px;
    padding: 5px 0;
    margin: 2px 0 0;
    font-size: 14px;
    text-align: left;
    list-style: none;
    background-color: #fff;
    -webkit-background-clip: padding-box;
    background-clip: padding-box;
    border: 1px solid #ccc;
    border: 1px solid rgba(0,0,0,.15);
    border-radius: 4px;
    -webkit-box-shadow: 0 6px 12px rgba(0,0,0,.175);
    box-shadow: 0 6px 12px rgba(0,0,0,.175);
}
</style>
<script>
$(document).ready(function () {
  window.initializeCodeFolding("show" === "show");
});
</script>
', sep = "\n"),
  paste0('
<script>
document.write(\'<div class="btn-group pull-right" style="position: absolute; top: 20%; right: 2%; z-index: 200"><button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true" data-_extension-text-contrast=""><span>Code</span> <span class="caret"></span></button><ul class="dropdown-menu" style="min-width: 50px;"><li><a id="rmd-show-all-code" href="#">Show All Code</a></li><li><a id="rmd-hide-all-code" href="#">Hide All Code</a></li></ul></div>\')
</script>
')
)

readr::write_lines(htmlhead, path = "/mnt/Data/autoentrepreneur/header.html")
```

新的全局按钮显示一个下拉菜单,可以在“显示所有代码”或“隐藏所有代码”之间进行选择。使用window.initializeCodeFolding("show" === "show")默认显示所有代码,使用window.initializeCodeFolding("show" === "hide")默认隐藏所有代码。

【讨论】:

  • 谢谢!这会在每个页面上添加一个按钮,我将如何为每个块添加一个按钮,就像在 rmarkdown 中一样?
  • 对不起,我目前正在尝试使用这个答案,但暂时没有成功:stackoverflow.com/questions/37944197/…。这可以与这个结合使用,以便在块中包含 css 类:stackoverflow.com/questions/37944197/…。如果我成功了,我会更新我的答案。
  • 我在当前“不工作”阶段添加了脚本,也许有人可以帮助看看是什么问题。
  • 好的,现在我找到了显示/隐藏每个代码块的解决方案。然后,您可以使用自己的 css 来显示漂亮的按钮。
  • 是的,您可以使用window.initializeCodeFolding("show" === "hide")。我还建议阅读有关它的完整博客文章:statnmap.com/…
【解决方案2】:

我制作了Rrtemps,其中包括一个带有代码折叠按钮 的即用型预订模板(主要基于 Sébastien Rochette 的回答/帖子)。检查它here

【讨论】:

  • 这真的很棒,谢谢。我喜欢代码面板平滑打开和关闭的方式。
【解决方案3】:

我为 pandoc 写了一个过滤器:

  • 将所有代码块包装在 HTML5 &lt;details&gt; 标签中
  • 添加一个本地按钮来折叠/展开代码
  • 按钮文本通过onclick javascript 事件在“显示代码”和“隐藏代码”(随意自定义)之间切换

过滤器可以找到here。需要安装了 panflutepython 分发版才能运行。

通过pandoc_args: ["-F", "path/to/collapse_code.py"]添加到预订

【讨论】:

    猜你喜欢
    • 2018-12-07
    • 1970-01-01
    • 2016-10-26
    • 2022-01-11
    • 2017-03-10
    • 1970-01-01
    • 2019-05-17
    • 2013-10-29
    相关资源
    最近更新 更多