-
-
Notifications
You must be signed in to change notification settings - Fork 31
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
Support for index page templating #168
Changes from 22 commits
f6c13a9
f81fcb5
a58d4f2
4d72243
30251cf
3346a93
2e58b37
0984660
3aa0f50
a2410d5
a158a37
1138e4c
fd67f8a
17a61d1
13ebec4
ab54aa0
ce4a8b6
036e4e5
09b0851
4023b67
8e98370
0ce3158
7fd1ebe
a0c2f7e
5ae7549
79b0faa
39d52e0
8b71875
f3dbfb9
e3a40c3
df3d780
84f8464
5bbba6e
2aef1f3
56904ba
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 |
---|---|---|
|
@@ -114,7 +114,55 @@ | |
#' present a warning and return `NULL` if the Dash app was not loaded via `source()` | ||
#' if the `DASH_APP_PATH` environment variable is undefined. | ||
#' } | ||
#' \item{`run_server(host = Sys.getenv('HOST', "127.0.0.1"), | ||
#' \item{`index_string(string)`}{ | ||
#' The `index_string` method allows the specification of a custom index by changing | ||
rpkyle marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#' the default `HTML` template that is generated by the Dash UI. Meta tags, CSS, Javascript, | ||
#' are some examples of features that can be modified..This method will present a warning if your | ||
#' HTML template is missing any necessary components and return an error if a valid index is not defined | ||
#' {%metas%} # optional - The registered meta tags. | ||
#' {%favicon%} # optional - A favicon link tag if found in `assets`. | ||
#' {%css%} # optional - link tags to css resources. | ||
#' {%config%} # required - Config generated by dash for the renderer. | ||
#' {%app_entry%} # required - The container where dash react components are rendered. | ||
#' {%scripts%} # required - Collected dependencies scripts tags. | ||
#' | ||
#' Example of a basic html index: | ||
#' "<!DOCTYPE html> | ||
#' <html> | ||
#' <head> | ||
#' {%meta_tags%} | ||
#' <title>{private$name}</title> | ||
#' {%favicon%} | ||
#' {%css_tags%} | ||
#' </head> | ||
#' <body> | ||
#' {%app_entry%} | ||
#' <footer> | ||
#' {%config%} | ||
#' {%scripts%} | ||
#' </footer> | ||
#' </body> | ||
#' </html>" | ||
#' | ||
#' \describe{ | ||
#' \item{string}{Character. A formatted string with a complete HTML index} | ||
#' } | ||
#' } | ||
#' \item{`interpolate_index(template_index, ...)`}{ | ||
#' With the `interpolate_index` method, we can pass a custom index with template string | ||
#' variables that are already evaluated. We can directly pass arguments to the `template_index` | ||
#' by assigning them to variables present in the template. This is similar to the `index_string` method | ||
#' but offers the ability to change the default components of the Dash index as seen in the example below: | ||
#' | ||
#' """ | ||
#' app$interpolate_index(template_index, metas = "<meta_charset='UTF-8'/>", renderer = renderer, config = config) | ||
#' \describe{ | ||
#' \item{template_index}{Character. A formatted string with the HTML index string. Defaults to the initial template} | ||
#' \item{unnamed arguments}{Named List. These can be passed as individual named lists corresponding to the components | ||
#' of the Dash html index. These include the same arguments as those found in the `index_string()` template.} | ||
#' } | ||
#' } | ||
#' \item{`run_server(host = Sys.getenv('HOST', "127.0.0.1"), | ||
#' port = Sys.getenv('PORT', 8050), block = TRUE, showcase = FALSE, ...)`}{ | ||
#' The `run_server` method has 13 formal arguments, several of which are optional: | ||
#' \describe{ | ||
|
@@ -763,11 +811,53 @@ Dash <- R6::R6Class( | |
sep="/"))) | ||
}, | ||
|
||
# ------------------------------------------------------------------------ | ||
# specify a custom index string | ||
# ------------------------------------------------------------------------ | ||
index_string = function(string) { | ||
requiredKeys <- c("app_entry", "config", "scripts") | ||
|
||
checks <- sapply(requiredKeys, function(x) grepl(x, string)) | ||
|
||
if (FALSE %in% checks) { | ||
stop(sprintf("Did you forget to include %s in your index string?", | ||
paste(requiredKeys[!checks], collapse = ", "))) | ||
} | ||
private$custom_index = string | ||
}, | ||
rpkyle marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# ------------------------------------------------------------------------ | ||
# modify the templated variables by using the `interpolate_index` method. | ||
# ------------------------------------------------------------------------ | ||
interpolate_index = function(template_index = private$template_index[[1]], ...) { | ||
template = template_index | ||
kwargs <- list(...) | ||
|
||
for (name in names(kwargs)) { | ||
key = paste0('\\{\\%', name, '\\%\\}') | ||
template = sub(key, kwargs[[name]], template) | ||
} | ||
|
||
cat(template) | ||
rpkyle marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
requiredKeys <- c("app_entry", "config", "scripts") | ||
rpkyle marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
checks <- sapply(requiredKeys, function(x) grepl(x, names(kwargs))) | ||
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. Nice, this is creative -- I wouldn't have thought of doing it this way. I wonder if this might be a little more succinct, though; you try something like
For generating the vector of booleans (logicals), I'd suggest using 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 think I found a way to make this a little more concise in 5ae7549. |
||
|
||
if (FALSE %in% checks) { | ||
stop(sprintf("Did you forget to include %s in your index string?", | ||
paste(requiredKeys[!checks], collapse = ", "))) | ||
} | ||
|
||
private$template_index = template | ||
}, | ||
|
||
# ------------------------------------------------------------------------ | ||
# convenient fiery wrappers | ||
# ------------------------------------------------------------------------ | ||
run_server = function(host = Sys.getenv('HOST', "127.0.0.1"), | ||
port = Sys.getenv('PORT', 8050), | ||
|
||
block = TRUE, | ||
showcase = FALSE, | ||
use_viewer = FALSE, | ||
|
@@ -1266,6 +1356,24 @@ Dash <- R6::R6Class( | |
|
||
# akin to https://github.com/plotly/dash/blob/d2ebc837/dash/dash.py#L338 | ||
# note discussion here https://github.com/plotly/dash/blob/d2ebc837/dash/dash.py#L279-L284 | ||
custom_index = NULL, | ||
template_index = c( | ||
"<!DOCTYPE html> | ||
<html> | ||
<head> | ||
{%meta_tags%} | ||
<title>{%private$name%}</title> | ||
{%favicon%} | ||
{%css_tags%} | ||
</head> | ||
<body> | ||
{%app_entry%} | ||
<footer> | ||
{%config%} | ||
{%scripts%} | ||
</footer> | ||
</body> | ||
</html>", NA), | ||
.index = NULL, | ||
|
||
generateReloadHash = function() { | ||
|
@@ -1434,13 +1542,29 @@ Dash <- R6::R6Class( | |
css_tags <- all_tags[["css_tags"]] | ||
|
||
# retrieve script tags for serving in the index | ||
scripts_tags <- all_tags[["scripts_tags"]] | ||
scripts <- all_tags[["scripts_tags"]] | ||
|
||
# insert meta tags if present | ||
meta_tags <- all_tags[["meta_tags"]] | ||
|
||
# define the react-entry-point | ||
app_entry <- "<div id='react-entry-point'><div class='_dash-loading'>Loading...</div></div>" | ||
# define the dash default config key | ||
config <- sprintf("<script id='_dash-config' type='application/json'> %s </script>", to_JSON(self$config)) | ||
|
||
if (!is.null(private$custom_index)) { | ||
string_index <- glue::glue(private$custom_index, .open = "{%", .close = "%}") | ||
|
||
private$.index <- string_index | ||
} | ||
|
||
else if (length(private$template_index) == 1) { | ||
private$.index <- private$template_index | ||
} | ||
|
||
private$.index <- sprintf( | ||
'<!DOCTYPE html> | ||
else { | ||
private$.index <- sprintf( | ||
'<!DOCTYPE html> | ||
<html> | ||
<head> | ||
%s | ||
|
@@ -1450,23 +1574,22 @@ Dash <- R6::R6Class( | |
</head> | ||
|
||
<body> | ||
<div id="react-entry-point"> | ||
<div class="_dash-loading">Loading...</div> | ||
</div> | ||
|
||
%s | ||
<footer> | ||
<script id="_dash-config" type="application/json"> %s </script> | ||
%s | ||
%s | ||
</footer> | ||
</body> | ||
</html>', | ||
meta_tags, | ||
private$name, | ||
favicon, | ||
css_tags, | ||
to_JSON(self$config), | ||
scripts_tags | ||
) | ||
meta_tags, | ||
private$name, | ||
favicon, | ||
css_tags, | ||
app_entry, | ||
config, | ||
scripts | ||
) | ||
} | ||
} | ||
) | ||
) | ||
|
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.
🎉