├── .gitignore ├── LICENSE ├── inst └── js │ ├── atLoad.js │ └── codefolder.js ├── NAMESPACE ├── .Rbuildignore ├── .travis.yml ├── codefolder.Rproj ├── man └── generic.Rd ├── DESCRIPTION ├── LICENSE.md ├── CODE_OF_CONDUCT.md ├── R └── fold.R ├── README.md └── README.Rmd /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2019 2 | COPYRIGHT HOLDER: Ian Lyttle 3 | -------------------------------------------------------------------------------- /inst/js/atLoad.js: -------------------------------------------------------------------------------- 1 | 2 | window.addEventListener('load', function () { 3 | codefolder('${query}'); 4 | }); 5 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(bookdown) 4 | export(distill) 5 | export(generic) 6 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^codefolder\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^LICENSE\.md$ 4 | ^README\.Rmd$ 5 | ^CODE_OF_CONDUCT\.md$ 6 | ^\.travis\.yml$ 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # R for travis: see documentation at https://docs.travis-ci.com/user/languages/r 2 | 3 | language: R 4 | sudo: false 5 | cache: packages 6 | 7 | matrix: 8 | include: 9 | - r: devel 10 | - r: release 11 | - r: oldrel 12 | -------------------------------------------------------------------------------- /codefolder.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageRoxygenize: rd,collate,namespace 22 | -------------------------------------------------------------------------------- /inst/js/codefolder.js: -------------------------------------------------------------------------------- 1 | 2 | function codefolder(query) { 3 | 4 | var x = document.querySelectorAll(query); 5 | if (x.length === 0) return; 6 | 7 | function toggle_vis(o) { 8 | var d = o.style.display; 9 | o.style.display = (d === 'block' || d === '') ? 'none':'block'; 10 | } 11 | 12 | for (i = 0; i < x.length; i++) { 13 | var y = x[i]; 14 | toggle_vis(y); 15 | } 16 | 17 | var elem = document.getElementById("codefolder-button"); 18 | if (elem.value === "Hide Code") elem.value = "Show Code"; 19 | else elem.value = "Hide Code"; 20 | } 21 | -------------------------------------------------------------------------------- /man/generic.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fold.R 3 | \name{generic} 4 | \alias{generic} 5 | \alias{bookdown} 6 | \alias{distill} 7 | \title{Enable code-folding} 8 | \usage{ 9 | generic(init = c("show", "hide"), query, style) 10 | 11 | bookdown(init = c("show", "hide"), query = "pre.sourceCode", 12 | style = "position: absolute; right: 8\%; z-index: 200") 13 | 14 | distill(init = c("show", "hide"), query = "d-code", style = "") 15 | } 16 | \arguments{ 17 | \item{init}{\code{character} indictates to \code{"show"} or \code{"hide"} code blocks 18 | at initialization.} 19 | 20 | \item{query}{\code{character} CSS-selector string for code blocks.} 21 | 22 | \item{style}{\code{character} CSS style for the button.} 23 | } 24 | \value{ 25 | \code{htmltools::tagList} 26 | } 27 | \description{ 28 | Enable code-folding 29 | } 30 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: codefolder 2 | Title: Enable per-page code-folding for Bookdown and Distill 3 | Version: 0.0.0.9000 4 | Authors@R: c( 5 | person( 6 | given = "Ian J", 7 | family = "Lyttle", 8 | role = c("aut", "cre"), 9 | email = "ian.lyttle@schneider-electric.com", 10 | comment = c(ORCID = "0000-0001-9962-4849") 11 | ), 12 | person( 13 | given = "Sébastien", 14 | family = "Rochette", 15 | role = c("ctb"), 16 | email = "sebastien@thinkr.fr" 17 | ) 18 | ) 19 | Description: Neither the distill package nor the bookdown package 20 | support code-folding natively. This is an attempt to make this a 21 | little easier in the meantime. It is based on this Stack Overflow 22 | answer: by Sébastien Rochette. 23 | License: MIT + file LICENSE 24 | Encoding: UTF-8 25 | LazyData: true 26 | Roxygen: list(markdown = TRUE) 27 | RoxygenNote: 6.1.1 28 | Imports: 29 | htmltools, 30 | glue 31 | URL: https://github.com/ijlyttle/codefolder 32 | BugReports: https://github.com/ijlyttle/codefolder/issues 33 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2019 Ian Lyttle 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, we pledge to respect all people who 4 | contribute through reporting issues, posting feature requests, updating documentation, 5 | submitting pull requests or patches, and other activities. 6 | 7 | We are committed to making participation in this project a harassment-free experience for 8 | everyone, regardless of level of experience, gender, gender identity and expression, 9 | sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion. 10 | 11 | Examples of unacceptable behavior by participants include the use of sexual language or 12 | imagery, derogatory comments or personal attacks, trolling, public or private harassment, 13 | insults, or other unprofessional conduct. 14 | 15 | Project maintainers have the right and responsibility to remove, edit, or reject comments, 16 | commits, code, wiki edits, issues, and other contributions that are not aligned to this 17 | Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed 18 | from the project team. 19 | 20 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by 21 | opening an issue or contacting one or more of the project maintainers. 22 | 23 | This Code of Conduct is adapted from the Contributor Covenant 24 | (https://www.contributor-covenant.org), version 1.0.0, available at 25 | https://contributor-covenant.org/version/1/0/0/. 26 | -------------------------------------------------------------------------------- /R/fold.R: -------------------------------------------------------------------------------- 1 | #' Enable code-folding 2 | #' 3 | #' @param init `character` indictates to `"show"` or `"hide"` code blocks 4 | #' at initialization. 5 | #' @param query `character` CSS-selector string for code blocks. 6 | #' @param style `character` CSS style for the button. 7 | #' 8 | #' @return `htmltools::tagList` 9 | #' @export 10 | #' 11 | generic <- function(init = c("show", "hide"), query, style) { 12 | 13 | init <- match.arg(init) 14 | 15 | tag_init <- NULL 16 | if (identical(init, "hide")) { 17 | tag_init <- at_load(query) 18 | } 19 | 20 | htmltools::tagList( 21 | button(query, style = style), 22 | codefolder_script(), 23 | tag_init 24 | ) 25 | } 26 | 27 | #' @rdname generic 28 | #' @export 29 | #' 30 | bookdown <- function(init = c("show", "hide"), query = "pre.sourceCode", 31 | style = "position: absolute; right: 8%; z-index: 200") { 32 | 33 | init <- match.arg(init) 34 | 35 | generic(init, query = query, style = style) 36 | } 37 | 38 | #' @rdname generic 39 | #' @export 40 | #' 41 | distill <- function(init = c("show", "hide"), query = "d-code", style = "") { 42 | 43 | init <- match.arg(init) 44 | 45 | generic(init, query = query, style = style) 46 | } 47 | 48 | button <- function(query, style) { 49 | 50 | htmltools::tags$input( 51 | onclick = glue::glue("codefolder('{query}');"), 52 | type = "button", 53 | value = "Hide Code", 54 | id = "codefolder-button", 55 | style = style 56 | ) 57 | } 58 | 59 | codefolder_script <- function() { 60 | 61 | text <- 62 | glue::glue_collapse( 63 | c(readLines(system.file("js/codefolder.js", package = "codefolder")), ""), 64 | sep = "\n" 65 | ) 66 | 67 | htmltools::tags$script(htmltools::HTML(text)) 68 | } 69 | 70 | at_load <- function(query) { 71 | 72 | text <- 73 | glue::glue( 74 | glue::glue_collapse( 75 | c(readLines(system.file("js/atLoad.js", package = "codefolder")), ""), 76 | sep = "\n" 77 | ), 78 | .open = "${", 79 | .trim = FALSE 80 | ) 81 | 82 | htmltools::tags$script(htmltools::HTML(text)) 83 | } 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # codefolder 5 | 6 | 7 | 8 | [![CRAN 9 | status](https://www.r-pkg.org/badges/version/codefolder)](https://CRAN.R-project.org/package=codefolder) 10 | [![Lifecycle: 11 | experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://www.tidyverse.org/lifecycle/#experimental) 12 | [![Travis build 13 | status](https://travis-ci.org/ijlyttle/codefolder.svg?branch=master)](https://travis-ci.org/ijlyttle/codefolder) 14 | 15 | 16 | The goal of codefolder is to provide “aftermarket” code-folding 17 | capabilty for [bookdown](https://bookdown.org/yihui/bookdown) and 18 | [distill](https://rstudio.github.io/distill). The operative code is 19 | based on this Stack Overflow 20 | [answer](https://stackoverflow.com/a/45501553) by Sébastien Rochette. 21 | 22 | ## Installation 23 | 24 | You can install the delevopment version of codefolder from 25 | [GitHub](https://github.com/ijlyttle/codefolder) with: 26 | 27 | ``` r 28 | # install.packages("devtools") 29 | devtools::install_github("ijlyttle/codefolder") 30 | ``` 31 | 32 | ## Example 33 | 34 | This is a quick way to enable code-folding, for an entire page, on a 35 | page-by-page basis. 36 | 37 | The idea is to put an Rmd-chunk near the top of a page. When rendered, 38 | the chunk places a button in the right margin which can be used to show 39 | or hide code. 40 | 41 | There is a function each for Bookdown and Distill. The main argument is 42 | `init`, which indicates if you want, initially, to `"show"` or `"hide"` 43 | the code. The other arguments are `query`, the CSS selector for to match 44 | the code elements, and the `style` to the button. 45 | 46 | Bookdown: 47 | 48 | ```{r codefolder, echo=FALSE, results='asis'} 49 | codefolder::bookdown(init = "hide") 50 | ``` 51 | 52 | Distill: 53 | 54 | 59 | 60 | If you like, you can create these as RStudio [code 61 | snippets](https://support.rstudio.com/hc/en-us/articles/204463668-Code-Snippets) 62 | for markdown. I use `cfb` and `cfd` as my short-codes. 63 | 64 | It will be up to you to add some CSS according to your tastes. 65 | 66 | ## Code of Conduct 67 | 68 | Please note that the ‘codefolder’ project is released with a 69 | [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By contributing to 70 | this project, you agree to abide by its terms. 71 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r, include = FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = TRUE, 10 | comment = "#>", 11 | fig.path = "man/figures/README-", 12 | out.width = "100%" 13 | ) 14 | ``` 15 | 16 | # codefolder 17 | 18 | 19 | [![CRAN status](https://www.r-pkg.org/badges/version/codefolder)](https://CRAN.R-project.org/package=codefolder) 20 | [![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://www.tidyverse.org/lifecycle/#experimental) 21 | [![Travis build status](https://travis-ci.org/ijlyttle/codefolder.svg?branch=master)](https://travis-ci.org/ijlyttle/codefolder) 22 | 23 | 24 | The goal of codefolder is to provide "aftermarket" code-folding capabilty for [bookdown](https://bookdown.org/yihui/bookdown) and [distill](https://rstudio.github.io/distill). The operative code is based on this Stack Overflow [answer](https://stackoverflow.com/a/45501553) by Sébastien Rochette. 25 | 26 | ## Installation 27 | 28 | You can install the delevopment version of codefolder from [GitHub](https://github.com/ijlyttle/codefolder) with: 29 | 30 | ``` r 31 | # install.packages("devtools") 32 | devtools::install_github("ijlyttle/codefolder") 33 | ``` 34 | 35 | ## Example 36 | 37 | This is a quick way to enable code-folding, for an entire page, on a page-by-page basis. 38 | 39 | The idea is to put an Rmd-chunk near the top of a page. When rendered, the chunk places a button in the right margin which can be used to show or hide code. 40 | 41 | There is a function each for Bookdown and Distill. The main argument is `init`, which indicates if you want, initially, to `"show"` or `"hide"` the code. The other arguments are `query`, the CSS selector for to match the code elements, and the `style` to the button. 42 | 43 | Bookdown: 44 | 45 | ```` 46 | `r ''````{r codefolder, echo=FALSE, results='asis'} 47 | codefolder::bookdown(init = "hide") 48 | ``` 49 | ```` 50 | 51 | Distill: 52 | 53 | ```` 54 | 59 | ```` 60 | 61 | If you like, you can create these as RStudio [code snippets](https://support.rstudio.com/hc/en-us/articles/204463668-Code-Snippets) for markdown. I use `cfb` and `cfd` as my short-codes. 62 | 63 | It will be up to you to add some CSS according to your tastes. 64 | 65 | ## Code of Conduct 66 | 67 | Please note that the 'codefolder' project is released with a 68 | [Contributor Code of Conduct](CODE_OF_CONDUCT.md). 69 | By contributing to this project, you agree to abide by its terms. 70 | --------------------------------------------------------------------------------