From 61db7a9f5b18d77609877e3a3a039758b17d554a Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Thu, 4 Mar 2021 17:47:49 +0100 Subject: [PATCH] Allow to add specific shiny-prerendered parts in HTML template (#2064) A new pandoc variable `shiny-prerendered` is set when rendering a shiny prerendered document. This allow to add specific content for this type of rendered document in an HTML template. It is used in all HTML templates to add a special comment `` required by htmltools / shiny to reinsert the HTML dependencies. Following #1942, it was put by default at the end of the error which caused issue in leanr, e.g rstudio/learnr#499 This will fix #2060 following change in 49c0c2b. --- DESCRIPTION | 2 +- NEWS.md | 2 +- R/render.R | 4 ++ R/shiny_prerendered.R | 15 ++++++-- inst/rmd/h/default.html | 3 ++ inst/rmd/ioslides/default.html | 3 ++ inst/rmd/slidy/default.html | 3 ++ tests/testthat/helpers.R | 28 ++++++++++++-- tests/testthat/test-lua-filters.R | 4 +- tests/testthat/test-shiny.R | 19 ++------- tests/testthat/test-shiny_prerendered.R | 51 +++++++++++++++++++++++++ 11 files changed, 105 insertions(+), 29 deletions(-) create mode 100644 tests/testthat/test-shiny_prerendered.R diff --git a/DESCRIPTION b/DESCRIPTION index c10e96667d..ca431ce838 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: rmarkdown Type: Package Title: Dynamic Documents for R -Version: 2.7.2 +Version: 2.7.3 Authors@R: c( person("JJ", "Allaire", role = "aut", email = "jj@rstudio.com"), person("Yihui", "Xie", role = c("aut", "cre"), email = "xie@yihui.name", comment = c(ORCID = "0000-0003-0645-5666")), diff --git a/NEWS.md b/NEWS.md index 8ff2e4d477..9c798e83f1 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,7 +3,7 @@ rmarkdown 2.8 - Provided a `runtime: shiny` fix for output formats that pass a modified `bslib::bs_theme()` object to `html_document_base()`'s `theme` (thanks, @cpsievert, #2049). -- Rendering using `runtime: shiny_prerendered` will now produce valid HTML by not inserting anymore the full document as body in the resulting shiny apps. (thanks, @dakep, #1942). +- Rendering using `runtime: shiny_prerendered` or `runtime: shinyrmd` will now produce valid HTML by not inserting anymore the full document as body in the resulting shiny apps (thanks, @dakep, #1912). Header content usually containing html dependencies will be inserted in the HTML document at the end of the head before ``, unless the rendered HTML contains `` special comment (see `htmltools::renderDocument()`). A new Pandoc variable is set in for shiny prerendered document to allow conditional insertion of such content in the the HTML template using `$if(shiny-prerendered)$`. This has been done in all HTML template in this package. Users of custom template should make this change to provide support for this runtime. See **rmarkdown** default template (`default.html`) for an example (#2064). rmarkdown 2.7 ================================================================================ diff --git a/R/render.R b/R/render.R index d3645b4f90..bfc23550b3 100644 --- a/R/render.R +++ b/R/render.R @@ -844,6 +844,10 @@ render <- function(input, shiny_prerendered_dependencies, files_dir, output_dir) + # indicate to Pandoc we are in a shiny prerendered document to activate + # specific parts in the template. + output_format$pandoc$args <- c(output_format$pandoc$args, + pandoc_variable_arg("shiny-prerendered")) } perf_timer_stop("pre-processor") diff --git a/R/shiny_prerendered.R b/R/shiny_prerendered.R index ba1d554df8..c7fd940b82 100644 --- a/R/shiny_prerendered.R +++ b/R/shiny_prerendered.R @@ -160,13 +160,20 @@ shiny_prerendered_html <- function(input_rmd, render_args) { # return html w/ dependencies html_with_deps <- shinyHTML_with_deps(rendered_html, dependencies) - # add placeholder for additional dependencies at the end of the element - # using a template expansion expected by shiny (usually done in shiny:::renderPage) - sub('', - paste0('\n', htmltools::htmlTemplate(text_ = "{{ headContent() }}"), '\n'), + # The html template used to render the UI should contain the placeholder + # expected by shiny in `shiny:::renderPage()` which uses + # `htmltools::renderDocument`. + # If it is not present in the template, we add this placeholder at the end of + # the element + if (!any(grepl(headContent <- "", html_with_deps, fixed = TRUE))) { + html_with_deps <- sub( + '', + paste0('\n', headContent, '\n'), html_with_deps, fixed = TRUE, useBytes = TRUE) + } + html_with_deps } shiny_prerendered_ui <- function(html, deps) { diff --git a/inst/rmd/h/default.html b/inst/rmd/h/default.html index 39a8db77b7..49e9342f5c 100644 --- a/inst/rmd/h/default.html +++ b/inst/rmd/h/default.html @@ -26,6 +26,9 @@ $for(header-includes)$ $header-includes$ $endfor$ +$if(shiny-prerendered)$ + +$endif$