Search code examples
cssrrstudiobookdown

how to include blocks that appear and disappear in html using css


I am using bookdown (html) instead of slides in lectures. I really would like to create blocks that appear/disappear to include questions` solutions. Probably I can do it by css. But I do not now how to do this and also include my css without mess with the bookdown css

Example:

Question: bla bla bla ?

Solution uncover

When I click in uncover I could show my R code and output. That would be great :)


Solution

  • You can achieve what you want through the knitr hooks. When you set a hook option for code chunk (in this example uncover = TRUE), it will trigger the corresponding hook function uncover, and the hook can write something before and after the html code generated from the chunk output.

    In the code below, I first define a Javascript function function uncover(id) which can uncover certain html element by id. And I let the hook uncover to generate a html button which calls the Javascript function before the chunk output and wrap the output with a div with certain id and style.display =none`. You can make modification to the code below to adapt to your need, but the idea is like this.

    ```{r setup, include=FALSE}
    knitr::opts_chunk$set(echo = TRUE)
    uncover <- function(before, options, envir) {
        if (before) {
            id <- options$id
            button_string <- paste0("<button onclick=\"uncover('", 
                                    id, 
                                    "')\">Uncover</button>")
            div_string <- paste0("<div id = '", id, 
                                 "', style = 'display:none'>")
            paste0(button_string, "\n", div_string)
        }
        else {
            "</div>"
        }
    }
    
    knitr::knit_hooks$set(uncover = uncover)
    ```
    <script>
    function uncover(id) {
        var x = document.getElementById(id);
        x.style.display = 'block';
    }
    </script>
    
    ```{r, uncover = TRUE, id = "script"}
    1 + 1
    ```
    

    Edit at 05/03/2020 Currently, knitr or pandoc or something else in the toolchain refuses to convert invisible markdown elements into valid HTML, so the solution above does not work perfectly. One solution is to make all the things visible at first, but provide a button to hide them like the following:

    ```{r setup, include=FALSE}
    knitr::opts_chunk$set(echo = TRUE)
    uncover <- function(before, options, envir) {
        if (before) {
         id <- options$id
            button_string <- paste0("<button onclick=\"uncover('", 
                                    id, 
                                    "')\">Uncover</button>")
            div_string <- paste0("<div id = '", id, 
                                 "' class = 'cover'>")
            paste0(button_string, "\n", div_string)
        }
        else {
            "</div>"
        }
    }
    
    knitr::knit_hooks$set(uncover = uncover)
    ```
    
    ```{r, uncover = TRUE, id = "script"}
    1 + 1
    ```
    
    <script>
    function uncover(id) {
        var x = document.getElementById(id);
        x.style.display = 'block';
    }
    
    function cover() {
        var xs = document.getElementsByClassName('cover');
        for(count = 0; count < xs.length; count++) {
            xs[count].style.display = 'none';
        }
    }
    </script>
    
    <button onclick="cover()">Cover all</button>