-
-
Notifications
You must be signed in to change notification settings - Fork 979
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inject CSS styling into RMD parametrization app #866
base: main
Are you sure you want to change the base?
Changes from all commits
2858c1f
90b0ada
b0961f4
78958a6
99e714d
202f3e9
c1ab123
cfec064
7f4acd0
b8bb6f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -185,6 +185,56 @@ params_namedList <- function() { | |
empty | ||
} | ||
|
||
|
||
params_html_head <- function(html_head_style = c(), | ||
html_head_script = c(), | ||
html_head_style_link = c(), | ||
html_head_script_link = c()) { | ||
|
||
default_style <- shiny::tags$style( | ||
# Our controls are wiiiiide. | ||
".container-fluid .shiny-input-container { width: auto; }", | ||
# Prevent the save/cancel buttons from squashing together. | ||
".navbar button { margin-left: 10px; }", | ||
# Style for the navbar footer. | ||
# http://getbootstrap.com/components/#navbar-fixed-bottom | ||
"body { padding-bottom: 70px; }" | ||
) | ||
## Escape is "cancel" and Enter is "save". | ||
default_script <- shiny::tags$script(shiny::HTML("$(document).keyup(function(e) {\n", | ||
"if (e.which == 13) { $('#save').click(); } // enter\n", | ||
"if (e.which == 27) { $('#cancel').click(); } // esc\n", | ||
"});" | ||
)) | ||
|
||
html_head_style <- as.vector(html_head_style) | ||
custom_styles <- lapply(html_head_style, shiny::tags$style) | ||
|
||
html_head_script <- as.vector(html_head_script) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why the a <- c(1,2)
lapply(a, function(b) b*2)
lapply(as.vector(a), function(b) b*2) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, sorry, when I replied in the email, it put the comments in the wrong place.
|
||
custom_scripts <- lapply(html_head_script, function(x) shiny::tags$script(shiny::HTML(x))) | ||
|
||
html_head_style_link <- as.vector(html_head_style_link) | ||
custom_style_links <- lapply(html_head_style_link, function(x) shiny::tags$link(href = x)) | ||
|
||
html_head_script_link <- as.vector(html_head_script_link) | ||
custom_script_links <- lapply(html_head_script_link, function(x) shiny::tags$script(src = x)) | ||
|
||
return (do.call( | ||
shiny::tags$head, | ||
append( | ||
list(default_style, default_script), | ||
c( | ||
custom_style_links, | ||
custom_styles, | ||
custom_script_links, | ||
custom_scripts | ||
) | ||
) | ||
)) | ||
# default_style, custom_styles[0], default_script)) | ||
} | ||
|
||
|
||
#' Run a shiny application asking for parameter configuration for the given document. | ||
#' | ||
#' @param file Path to the R Markdown document with configurable parameters. | ||
|
@@ -193,6 +243,13 @@ params_namedList <- function() { | |
#' @param shiny_args Additional arguments to \code{\link[shiny:runApp]{runApp}}. | ||
#' @param save_caption Caption to use use for button that saves/confirms parameters. | ||
#' @param encoding The encoding of the input file; see \code{\link{file}}. | ||
#' @param html_head_style a string or a list/vector of strings representing CSS style that will be injected in the HTML HEAD. | ||
#' @param html_head_script a string or a list/vector of strings representing JS scripts that will be injected in the HTML HEAD. | ||
#' @param html_head_style_link same as above except that these are interpreted as HREF attributes in LINK tags. | ||
#' You must take care to unsure that the URL is absolute. | ||
#' @param html_head_script_link same as above except that these are interpreted as SRC attributes in SCRIPT tags. | ||
#' You must take care to unsure that the URL is absolute. | ||
#' @param disable_bootstrap if true, does not inject boostrap scripts and styles in the HTML HEAD. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know what the common formatting is for this package, but you could consider styling with |
||
#' | ||
#' @return named list with overridden parameter names and value. | ||
#' | ||
|
@@ -202,7 +259,12 @@ knit_params_ask <- function(file = NULL, | |
params = NULL, | ||
shiny_args = NULL, | ||
save_caption = "Save", | ||
encoding = getOption("encoding")) { | ||
encoding = getOption("encoding"), | ||
html_head_style = c(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One option that won't pollute the argument list so much is to have a single argument that accepts a named list. html_head = list() Then, if you want to specify some parts: html_head = list(style = "body { font-size: 15px; }") Not sure which would be preferred. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, when I replied in the email, it put the comments in the wrong place. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could indeed go either way. I agree with @trestletech that R tends to stylistically prefer long argument lists. Even though this isn't normally good form in more well decomposed systems in R where many operations tend to be top level "one button" ones it makes some sense (also forces documentation of the parameters in .Rd as a side benefit). |
||
html_head_script = c(), | ||
html_head_style_link = c(), | ||
html_head_script_link = c(), | ||
disable_bootstrap = FALSE) { | ||
|
||
if (is.null(input_lines)) { | ||
if (is.null(file)) { | ||
|
@@ -402,23 +464,15 @@ knit_params_ask <- function(file = NULL, | |
class = "container-fluid"), | ||
class = "navbar navbar-default navbar-fixed-bottom") | ||
|
||
style <- shiny::tags$style( | ||
# Our controls are wiiiiide. | ||
".container-fluid .shiny-input-container { width: auto; }", | ||
# Prevent the save/cancel buttons from squashing together. | ||
".navbar button { margin-left: 10px; }", | ||
# Style for the navbar footer. | ||
# http://getbootstrap.com/components/#navbar-fixed-bottom | ||
"body { padding-bottom: 70px; }" | ||
) | ||
## Escape is "cancel" and Enter is "save". | ||
script <- shiny::tags$script(shiny::HTML("$(document).keyup(function(e) {\n", | ||
"if (e.which == 13) { $('#save').click(); } // enter\n", | ||
"if (e.which == 27) { $('#cancel').click(); } // esc\n", | ||
"});" | ||
)) | ||
ui <- shiny::bootstrapPage( | ||
shiny::tags$head(style, script), | ||
buildPage <- ifelse((is.null(disable_bootstrap) | !isTruthy(disable_bootstrap)), shiny::bootstrapPage, shiny::tagList) | ||
|
||
ui <- buildPage( | ||
params_html_head( | ||
html_head_style = html_head_style, | ||
html_head_script = html_head_script, | ||
html_head_style_link = html_head_style_link, | ||
html_head_script_link = html_head_script_link | ||
), | ||
contents, | ||
footer) | ||
|
||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
context("params_html_head") | ||
|
||
anyHeadParams <- list( | ||
html_head_style="style", | ||
html_head_style_link = "link", | ||
html_head_script = "script", | ||
html_head_script_link = "scriptjs" | ||
) | ||
|
||
test_that("adds default style and script", { | ||
result <- params_html_head()$children | ||
expect_equal(length(result), 2) | ||
expect_equal(result[[1]]$name, "style") | ||
expect_equal(result[[2]]$name, "script") | ||
}) | ||
|
||
test_that("adds custom style after default style", { | ||
result <- do.call(params_html_head, anyHeadParams)$children | ||
expect_equal(length(result), 6) | ||
expect_equal(result[[4]], shiny::tags$style("style")) | ||
}) | ||
|
||
test_that("adds custom style links after default but before inline custom styles", { | ||
result <- do.call(params_html_head, anyHeadParams)$children | ||
expect_equal(length(result), 6) | ||
expect_equal(result[[3]], shiny::tags$link(href = "link")) | ||
expect_equal(result[[4]], shiny::tags$style("style")) | ||
}) | ||
|
||
test_that("adds custom script links after default but before inline custom scripts", { | ||
result <- do.call(params_html_head, anyHeadParams)$children | ||
expect_equal(length(result), 6) | ||
expect_equal(result[[5]], shiny::tags$script(src = "scriptjs")) | ||
expect_equal(result[[6]], shiny::tags$script(shiny::HTML("script"))) | ||
}) | ||
|
||
test_that("can pass string as style link", { | ||
result <- params_html_head(html_head_style_link="link")$children | ||
expect_equal(result[[3]], shiny::tags$link(href = "link")) | ||
}) | ||
|
||
test_that("can pass vector of strings as style link", { | ||
result <- params_html_head(html_head_style_link=c("link"))$children | ||
expect_equal(result[[3]], shiny::tags$link(href = "link")) | ||
}) | ||
|
||
test_that("can pass string as style", { | ||
result <- params_html_head(html_head_style="style")$children | ||
expect_equal(result[[3]], shiny::tags$style("style")) | ||
}) | ||
|
||
test_that("can pass vector of strings as style", { | ||
result <- params_html_head(html_head_style=c("style"))$children | ||
expect_equal(result[[3]], shiny::tags$style("style")) | ||
}) | ||
|
||
test_that("can pass string as script", { | ||
result <- params_html_head(html_head_script="script")$children | ||
expect_equal(result[[3]], shiny::tags$script(shiny::HTML("script"))) | ||
}) | ||
|
||
test_that("can pass vector of strings as script", { | ||
result <- params_html_head(html_head_script=c("script"))$children | ||
expect_equal(result[[3]], shiny::tags$script(shiny::HTML("script"))) | ||
}) | ||
|
||
test_that("can pass string as script link", { | ||
result <- params_html_head(html_head_script_link="script")$children | ||
expect_equal(result[[3]], shiny::tags$script(src = "script")) | ||
}) | ||
|
||
test_that("can pass vector of strings as script link", { | ||
result <- params_html_head(html_head_script_link=c("script"))$children | ||
expect_equal(result[[3]], shiny::tags$script(src = "script")) | ||
}) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any situation where we will want to not inject the defaults?