Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f6c13a9
Dash for R v0.2.0 (#162)
rpkyle Jan 4, 2020
f81fcb5
Update README.md
rpkyle Jan 5, 2020
a58d4f2
Added initial implementation of index customization with strings
HammadTheOne Jan 9, 2020
4d72243
Fixed issue with `collect_assets` being undefined
HammadTheOne Jan 10, 2020
30251cf
Added description and details.
HammadTheOne Jan 10, 2020
3346a93
Added description
HammadTheOne Jan 14, 2020
2e58b37
Added error messages and warnings.
HammadTheOne Jan 14, 2020
0984660
Merge branch 'dev' into 42-index-page-templating
HammadTheOne Jan 14, 2020
3aa0f50
Updated version to 0.3.0
HammadTheOne Jan 16, 2020
a2410d5
Added CRLF
HammadTheOne Jan 16, 2020
a158a37
Updated environment variable names to `dev` versions.
HammadTheOne Jan 17, 2020
1138e4c
Improved error message function, made parity changes for index keys.
HammadTheOne Jan 17, 2020
fd67f8a
Added available keys to description.
HammadTheOne Jan 17, 2020
17a61d1
Parity changes to `app_entry` and `config` keys
HammadTheOne Jan 17, 2020
13ebec4
Cleaned up description.
HammadTheOne Jan 17, 2020
ab54aa0
Added `interpolate_str` helper function to `utils.R`
HammadTheOne Jan 17, 2020
ce4a8b6
Changes to default index, consolidating `_dash-config`
HammadTheOne Jan 17, 2020
036e4e5
Added template index and logic for choosing correct index.
HammadTheOne Jan 19, 2020
09b0851
Added description for `interpolate_index`.
HammadTheOne Jan 19, 2020
4023b67
Updated glue arguments in `index_string` method, added example index.
HammadTheOne Jan 27, 2020
8e98370
Update to `interpolate_index` to reflect changes to `index_string`.
HammadTheOne Jan 27, 2020
0ce3158
Bugfix, referenced correct private variable.
HammadTheOne Jan 27, 2020
7fd1ebe
Update R/dash.R
rpkyle Feb 6, 2020
a0c2f7e
:hocho: cat(template)
Feb 6, 2020
5ae7549
:camel: make concise
Feb 6, 2020
79b0faa
replace = with <-
Feb 6, 2020
39d52e0
:dromedary_camel: DRY up key validation logic
Feb 6, 2020
8b71875
:black_large_square: use invisible
Feb 6, 2020
f3dbfb9
use latest pkgs
Feb 11, 2020
e3a40c3
update package docs
Feb 11, 2020
df3d780
update docs; remove name, add title
Feb 11, 2020
84f8464
note title method
Feb 11, 2020
5bbba6e
:see_no_evil: need default app name
Feb 11, 2020
2aef1f3
:rotating_light: add integration tests
Feb 11, 2020
56904ba
fix ref for dcc
Feb 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions DESCRIPTION
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
Package: dash
Title: An Interface to the Dash Ecosystem for Authoring Reactive Web Applications
Version: 0.2.0
Version: 0.3.0
Authors@R: c(person("Chris", "Parmer", role = c("aut"), email = "chris@plot.ly"), person("Ryan Patrick", "Kyle", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-5829-9867"), email = "ryan@plot.ly"), person("Carson", "Sievert", role = c("aut"), comment = c(ORCID = "0000-0002-4958-2844")), person(family = "Plotly Technologies", role = "cph"))
Description: A framework for building analytical web applications, Dash offers a pleasant and productive development experience. No JavaScript required.
Depends:
R (>= 3.0.2)
Imports:
dashHtmlComponents (== 1.0.2),
Comment thread
rpkyle marked this conversation as resolved.
dashCoreComponents (== 1.6.0),
dashTable (== 4.5.1),
dashCoreComponents (== 1.8.0),
dashTable (== 4.6.0),
R6,
fiery (> 1.0.0),
routr (> 0.2.0),
Expand All@@ -32,8 +32,8 @@ Collate:
'print.R'
'internal.R'
Remotes: plotly/dash-html-components@55c3884,
Comment thread
rpkyle marked this conversation as resolved.
plotly/dash-core-components@c107e0f,
plotly/dash-table@3058bd5
plotly/dash-core-components@fc153b4,
plotly/dash-table@79d46ca
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Expand Down
2 changes: 1 addition & 1 deletion NAMESPACE
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,4 +27,4 @@ importFrom(routr,RouteStack)
importFrom(routr,ressource_route)
importFrom(stats,setNames)
importFrom(tools,file_ext)
importFrom(utils,getFromNamespace)
importFrom(utils,getFromNamespace)
175 changes: 154 additions & 21 deletions R/dash.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,7 @@
#' @usage Dash
#'
#' @section Constructor: Dash$new(
#' name = "dash",
#' name = NULL,
#' server = fiery::Fire$new(),
#' assets_folder = 'assets',
#' assets_url_path = '/assets',
Expand All@@ -24,7 +24,7 @@
#' @section Arguments:
#' \tabular{lll}{
#' `name` \tab \tab Character. The name of the Dash application (placed in the `<title>`
#' of the HTML page).\cr
#' of the HTML page). DEPRECATED; please use `index_string()` or `interpolate_index()` instead.\cr
#' `server` \tab \tab The web server used to power the application.
#' Must be a [fiery::Fire] object.\cr
#' `assets_folder` \tab \tab Character. A path, relative to the current working directory,
Expand DownExpand Up@@ -100,6 +100,9 @@
#' from the Dash backend. The latter may offer improved performance relative
#' to callbacks written in R.
#' }
#' \item{`title("dash")`}{
#' The title of the app. If no title is supplied, Dash for R will use 'dash'.
#' }
#' \item{`callback_context()`}{
#' The `callback_context` method permits retrieving the inputs which triggered
#' the firing of a given callback, and allows introspection of the input/state
Expand All@@ -114,7 +117,63 @@
#' 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)`}{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

#' The `index_string` method allows the specification of a custom index by changing
Comment thread
rpkyle marked this conversation as 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 elements
#' and return an error if a valid index is not defined. The following interpolation keys are
#' currently supported:
#' \describe{
#' \item{`{%metas%}`}{Optional - The registered meta tags.}
#' \item{`{%favicon%}`}{Optional - A favicon link tag if found in assets.}
#' \item{`{%css%}`}{Optional - Link tags to css resources.}
#' \item{`{%config%}`}{Required - Config generated by dash for the renderer.}
#' \item{`{%app_entry%}`}{Required - The container where dash react components are rendered.}
#' \item{`{%scripts%}`}{Required - Collected dependencies scripts tags.}
#' }
#' \describe{
#' \item{Example of a basic HTML index string:}{
#' \preformatted{
#' "<!DOCTYPE html>
#' <html>
#' <head>
#' \{\%meta_tags\%\}
#' <title>\{\{%css\%\}\}</title>
#' \{\%favicon\%\}
#' \{\%css_tags\%\}
#' </head>
#' <body>
#' \{\%app_entry\%\}
#' <footer>
#' \{\%config\%\}
#' \{\%scripts\%\}
#' </footer>
#' </body>
#' </html>"
#' }
#' }
#' }
#' }
#' \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:
#' \preformatted{
#' 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{...}{Named List. The unnamed arguments 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{
Expand DownExpand Up@@ -174,7 +233,7 @@ Dash <- R6::R6Class(
config = list(),

# i.e., the Dash$new() method
initialize = function(name = "dash",
initialize = function(name = NULL,
server = fiery::Fire$new(),
assets_folder = 'assets',
assets_url_path = '/assets',
Expand All@@ -191,13 +250,18 @@ Dash <- R6::R6Class(
suppress_callback_exceptions = FALSE) {

# argument type checking
assertthat::assert_that(is.character(name))
assertthat::assert_that(inherits(server, "Fire"))
assertthat::assert_that(is.logical(serve_locally))
assertthat::assert_that(is.logical(suppress_callback_exceptions))

# save relevant args as private fields
private$name <- name
if (!is.null(name)) {
warning(sprintf(
"The supplied application title, '%s', should be set using the title() method, or passed via index_string() or interpolate_index(); it has been ignored, and 'dash' will be used instead.",
name),
call. = FALSE
)
}
private$serve_locally <- serve_locally
private$eager_loading <- eager_loading
# remove leading and trailing slash(es) if present
Expand DownExpand Up@@ -763,11 +827,44 @@ Dash <- R6::R6Class(
sep="/")))
},

# ------------------------------------------------------------------------
# specify a custom index string
# ------------------------------------------------------------------------
index_string = function(string) {
private$custom_index <- validate_keys(string)
},
Comment thread
rpkyle marked this conversation as 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)
}

invisible(validate_keys(names(kwargs)))

private$template_index <- template
},

# ------------------------------------------------------------------------
# specify a custom title
# ------------------------------------------------------------------------
title = function(string = "dash") {
assertthat::assert_that(is.character(string))
private$name <- string
},

# ------------------------------------------------------------------------
# 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,
Expand DownExpand Up@@ -1266,6 +1363,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>{%title%}</title>
{%favicon%}
{%css_tags%}
</head>
<body>
{%app_entry%}
<footer>
{%config%}
{%scripts%}
</footer>
</body>
</html>", NA),
.index = NULL,

generateReloadHash = function() {
Expand DownExpand Up@@ -1434,13 +1549,32 @@ 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$name))
private$name <- 'dash'

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
Expand All@@ -1450,23 +1584,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
)
}
}
)
)
Expand Down
30 changes: 30 additions & 0 deletions R/utils.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -1270,3 +1270,33 @@ tryCompress <- function(request, response) {
}
return(response$compress())
}

interpolate_str <- function(index_template, ...) {
# This function takes an index string, along with
# user specified keys for the html keys of the index
# and sets the default values of the keys to the
# ones specified by the keys themselves, returning
# the custom index template.
template = index_template
kwargs <- list(...)

for (name in names(kwargs)) {
key = paste0('\\{', name, '\\}')

template = sub(key, kwargs[[name]], template)
}
return(template)
}

validate_keys <- function(string) {
required_keys <- c("app_entry", "config", "scripts")

keys_present <- vapply(required_keys, function(x) grepl(x, string), logical(1))

if (!all(keys_present)) {
stop(sprintf("Did you forget to include %s in your index string?",
paste(names(keys_present[keys_present==FALSE]), collapse = ", ")))
} else {
return(string)
}
}
2 changes: 1 addition & 1 deletion README.md
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
[![CircleCI](https://circleci.com/gh/plotly/dashR/tree/dev.svg?style=svg)](https://circleci.com/gh/plotly/dashR/tree/dev)
[![CircleCI](https://circleci.com/gh/plotly/dashR/tree/master.svg?style=svg)](https://circleci.com/gh/plotly/dashR/tree/master)
[![GitHub](https://img.shields.io/github/license/plotly/dashR.svg?color=dark-green)](https://github.com/plotly/dashR/blob/master/LICENSE)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/y/plotly/dashR.svg?color=dark-green)](https://github.com/plotly/dashR/graphs/contributors)

Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Support for index page templating by HammadTheOne · Pull Request #168 · plotly/dashR · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f6c13a9
Dash for R v0.2.0 (#162)
rpkyle Jan 4, 2020
f81fcb5
Update README.md
rpkyle Jan 5, 2020
a58d4f2
Added initial implementation of index customization with strings
HammadTheOne Jan 9, 2020
4d72243
Fixed issue with `collect_assets` being undefined
HammadTheOne Jan 10, 2020
30251cf
Added description and details.
HammadTheOne Jan 10, 2020
3346a93
Added description
HammadTheOne Jan 14, 2020
2e58b37
Added error messages and warnings.
HammadTheOne Jan 14, 2020
0984660
Merge branch 'dev' into 42-index-page-templating
HammadTheOne Jan 14, 2020
3aa0f50
Updated version to 0.3.0
HammadTheOne Jan 16, 2020
a2410d5
Added CRLF
HammadTheOne Jan 16, 2020
a158a37
Updated environment variable names to `dev` versions.
HammadTheOne Jan 17, 2020
1138e4c
Improved error message function, made parity changes for index keys.
HammadTheOne Jan 17, 2020
fd67f8a
Added available keys to description.
HammadTheOne Jan 17, 2020
17a61d1
Parity changes to `app_entry` and `config` keys
HammadTheOne Jan 17, 2020
13ebec4
Cleaned up description.
HammadTheOne Jan 17, 2020
ab54aa0
Added `interpolate_str` helper function to `utils.R`
HammadTheOne Jan 17, 2020
ce4a8b6
Changes to default index, consolidating `_dash-config`
HammadTheOne Jan 17, 2020
036e4e5
Added template index and logic for choosing correct index.
HammadTheOne Jan 19, 2020
09b0851
Added description for `interpolate_index`.
HammadTheOne Jan 19, 2020
4023b67
Updated glue arguments in `index_string` method, added example index.
HammadTheOne Jan 27, 2020
8e98370
Update to `interpolate_index` to reflect changes to `index_string`.
HammadTheOne Jan 27, 2020
0ce3158
Bugfix, referenced correct private variable.
HammadTheOne Jan 27, 2020
7fd1ebe
Update R/dash.R
rpkyle Feb 6, 2020
a0c2f7e
:hocho: cat(template)
Feb 6, 2020
5ae7549
:camel: make concise
Feb 6, 2020
79b0faa
replace = with <-
Feb 6, 2020
39d52e0
:dromedary_camel: DRY up key validation logic
Feb 6, 2020
8b71875
:black_large_square: use invisible
Feb 6, 2020
f3dbfb9
use latest pkgs
Feb 11, 2020
e3a40c3
update package docs
Feb 11, 2020
df3d780
update docs; remove name, add title
Feb 11, 2020
84f8464
note title method
Feb 11, 2020
5bbba6e
:see_no_evil: need default app name
Feb 11, 2020
2aef1f3
:rotating_light: add integration tests
Feb 11, 2020
56904ba
fix ref for dcc
Feb 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions DESCRIPTION
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
Package: dash
Title: An Interface to the Dash Ecosystem for Authoring Reactive Web Applications
Version: 0.2.0
Version: 0.3.0
Authors@R: c(person("Chris", "Parmer", role = c("aut"), email = "chris@plot.ly"), person("Ryan Patrick", "Kyle", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-5829-9867"), email = "ryan@plot.ly"), person("Carson", "Sievert", role = c("aut"), comment = c(ORCID = "0000-0002-4958-2844")), person(family = "Plotly Technologies", role = "cph"))
Description: A framework for building analytical web applications, Dash offers a pleasant and productive development experience. No JavaScript required.
Depends:
R (>= 3.0.2)
Imports:
dashHtmlComponents (== 1.0.2),
Comment thread
rpkyle marked this conversation as resolved.
dashCoreComponents (== 1.6.0),
dashTable (== 4.5.1),
dashCoreComponents (== 1.8.0),
dashTable (== 4.6.0),
R6,
fiery (> 1.0.0),
routr (> 0.2.0),
Expand All@@ -32,8 +32,8 @@ Collate:
'print.R'
'internal.R'
Remotes: plotly/dash-html-components@55c3884,
Comment thread
rpkyle marked this conversation as resolved.
plotly/dash-core-components@c107e0f,
plotly/dash-table@3058bd5
plotly/dash-core-components@fc153b4,
plotly/dash-table@79d46ca
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Expand Down
2 changes: 1 addition & 1 deletion NAMESPACE
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,4 +27,4 @@ importFrom(routr,RouteStack)
importFrom(routr,ressource_route)
importFrom(stats,setNames)
importFrom(tools,file_ext)
importFrom(utils,getFromNamespace)
importFrom(utils,getFromNamespace)
175 changes: 154 additions & 21 deletions R/dash.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,7 @@
#' @usage Dash
#'
#' @section Constructor: Dash$new(
#' name = "dash",
#' name = NULL,
#' server = fiery::Fire$new(),
#' assets_folder = 'assets',
#' assets_url_path = '/assets',
Expand All@@ -24,7 +24,7 @@
#' @section Arguments:
#' \tabular{lll}{
#' `name` \tab \tab Character. The name of the Dash application (placed in the `<title>`
#' of the HTML page).\cr
#' of the HTML page). DEPRECATED; please use `index_string()` or `interpolate_index()` instead.\cr
#' `server` \tab \tab The web server used to power the application.
#' Must be a [fiery::Fire] object.\cr
#' `assets_folder` \tab \tab Character. A path, relative to the current working directory,
Expand DownExpand Up@@ -100,6 +100,9 @@
#' from the Dash backend. The latter may offer improved performance relative
#' to callbacks written in R.
#' }
#' \item{`title("dash")`}{
#' The title of the app. If no title is supplied, Dash for R will use 'dash'.
#' }
#' \item{`callback_context()`}{
#' The `callback_context` method permits retrieving the inputs which triggered
#' the firing of a given callback, and allows introspection of the input/state
Expand All@@ -114,7 +117,63 @@
#' 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)`}{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

#' The `index_string` method allows the specification of a custom index by changing
Comment thread
rpkyle marked this conversation as 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 elements
#' and return an error if a valid index is not defined. The following interpolation keys are
#' currently supported:
#' \describe{
#' \item{`{%metas%}`}{Optional - The registered meta tags.}
#' \item{`{%favicon%}`}{Optional - A favicon link tag if found in assets.}
#' \item{`{%css%}`}{Optional - Link tags to css resources.}
#' \item{`{%config%}`}{Required - Config generated by dash for the renderer.}
#' \item{`{%app_entry%}`}{Required - The container where dash react components are rendered.}
#' \item{`{%scripts%}`}{Required - Collected dependencies scripts tags.}
#' }
#' \describe{
#' \item{Example of a basic HTML index string:}{
#' \preformatted{
#' "<!DOCTYPE html>
#' <html>
#' <head>
#' \{\%meta_tags\%\}
#' <title>\{\{%css\%\}\}</title>
#' \{\%favicon\%\}
#' \{\%css_tags\%\}
#' </head>
#' <body>
#' \{\%app_entry\%\}
#' <footer>
#' \{\%config\%\}
#' \{\%scripts\%\}
#' </footer>
#' </body>
#' </html>"
#' }
#' }
#' }
#' }
#' \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:
#' \preformatted{
#' 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{...}{Named List. The unnamed arguments 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{
Expand DownExpand Up@@ -174,7 +233,7 @@ Dash <- R6::R6Class(
config = list(),

# i.e., the Dash$new() method
initialize = function(name = "dash",
initialize = function(name = NULL,
server = fiery::Fire$new(),
assets_folder = 'assets',
assets_url_path = '/assets',
Expand All@@ -191,13 +250,18 @@ Dash <- R6::R6Class(
suppress_callback_exceptions = FALSE) {

# argument type checking
assertthat::assert_that(is.character(name))
assertthat::assert_that(inherits(server, "Fire"))
assertthat::assert_that(is.logical(serve_locally))
assertthat::assert_that(is.logical(suppress_callback_exceptions))

# save relevant args as private fields
private$name <- name
if (!is.null(name)) {
warning(sprintf(
"The supplied application title, '%s', should be set using the title() method, or passed via index_string() or interpolate_index(); it has been ignored, and 'dash' will be used instead.",
name),
call. = FALSE
)
}
private$serve_locally <- serve_locally
private$eager_loading <- eager_loading
# remove leading and trailing slash(es) if present
Expand DownExpand Up@@ -763,11 +827,44 @@ Dash <- R6::R6Class(
sep="/")))
},

# ------------------------------------------------------------------------
# specify a custom index string
# ------------------------------------------------------------------------
index_string = function(string) {
private$custom_index <- validate_keys(string)
},
Comment thread
rpkyle marked this conversation as 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)
}

invisible(validate_keys(names(kwargs)))

private$template_index <- template
},

# ------------------------------------------------------------------------
# specify a custom title
# ------------------------------------------------------------------------
title = function(string = "dash") {
assertthat::assert_that(is.character(string))
private$name <- string
},

# ------------------------------------------------------------------------
# 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,
Expand DownExpand Up@@ -1266,6 +1363,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>{%title%}</title>
{%favicon%}
{%css_tags%}
</head>
<body>
{%app_entry%}
<footer>
{%config%}
{%scripts%}
</footer>
</body>
</html>", NA),
.index = NULL,

generateReloadHash = function() {
Expand DownExpand Up@@ -1434,13 +1549,32 @@ 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$name))
private$name <- 'dash'

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
Expand All@@ -1450,23 +1584,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
)
}
}
)
)
Expand Down
30 changes: 30 additions & 0 deletions R/utils.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -1270,3 +1270,33 @@ tryCompress <- function(request, response) {
}
return(response$compress())
}

interpolate_str <- function(index_template, ...) {
# This function takes an index string, along with
# user specified keys for the html keys of the index
# and sets the default values of the keys to the
# ones specified by the keys themselves, returning
# the custom index template.
template = index_template
kwargs <- list(...)

for (name in names(kwargs)) {
key = paste0('\\{', name, '\\}')

template = sub(key, kwargs[[name]], template)
}
return(template)
}

validate_keys <- function(string) {
required_keys <- c("app_entry", "config", "scripts")

keys_present <- vapply(required_keys, function(x) grepl(x, string), logical(1))

if (!all(keys_present)) {
stop(sprintf("Did you forget to include %s in your index string?",
paste(names(keys_present[keys_present==FALSE]), collapse = ", ")))
} else {
return(string)
}
}
2 changes: 1 addition & 1 deletion README.md
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
[![CircleCI](https://circleci.com/gh/plotly/dashR/tree/dev.svg?style=svg)](https://circleci.com/gh/plotly/dashR/tree/dev)
[![CircleCI](https://circleci.com/gh/plotly/dashR/tree/master.svg?style=svg)](https://circleci.com/gh/plotly/dashR/tree/master)
[![GitHub](https://img.shields.io/github/license/plotly/dashR.svg?color=dark-green)](https://github.com/plotly/dashR/blob/master/LICENSE)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/y/plotly/dashR.svg?color=dark-green)](https://github.com/plotly/dashR/graphs/contributors)

Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Support for index page templating by HammadTheOne · Pull Request #168 · plotly/dashR · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f6c13a9
Dash for R v0.2.0 (#162)
rpkyle Jan 4, 2020
f81fcb5
Update README.md
rpkyle Jan 5, 2020
a58d4f2
Added initial implementation of index customization with strings
HammadTheOne Jan 9, 2020
4d72243
Fixed issue with `collect_assets` being undefined
HammadTheOne Jan 10, 2020
30251cf
Added description and details.
HammadTheOne Jan 10, 2020
3346a93
Added description
HammadTheOne Jan 14, 2020
2e58b37
Added error messages and warnings.
HammadTheOne Jan 14, 2020
0984660
Merge branch 'dev' into 42-index-page-templating
HammadTheOne Jan 14, 2020
3aa0f50
Updated version to 0.3.0
HammadTheOne Jan 16, 2020
a2410d5
Added CRLF
HammadTheOne Jan 16, 2020
a158a37
Updated environment variable names to `dev` versions.
HammadTheOne Jan 17, 2020
1138e4c
Improved error message function, made parity changes for index keys.
HammadTheOne Jan 17, 2020
fd67f8a
Added available keys to description.
HammadTheOne Jan 17, 2020
17a61d1
Parity changes to `app_entry` and `config` keys
HammadTheOne Jan 17, 2020
13ebec4
Cleaned up description.
HammadTheOne Jan 17, 2020
ab54aa0
Added `interpolate_str` helper function to `utils.R`
HammadTheOne Jan 17, 2020
ce4a8b6
Changes to default index, consolidating `_dash-config`
HammadTheOne Jan 17, 2020
036e4e5
Added template index and logic for choosing correct index.
HammadTheOne Jan 19, 2020
09b0851
Added description for `interpolate_index`.
HammadTheOne Jan 19, 2020
4023b67
Updated glue arguments in `index_string` method, added example index.
HammadTheOne Jan 27, 2020
8e98370
Update to `interpolate_index` to reflect changes to `index_string`.
HammadTheOne Jan 27, 2020
0ce3158
Bugfix, referenced correct private variable.
HammadTheOne Jan 27, 2020
7fd1ebe
Update R/dash.R
rpkyle Feb 6, 2020
a0c2f7e
:hocho: cat(template)
Feb 6, 2020
5ae7549
:camel: make concise
Feb 6, 2020
79b0faa
replace = with <-
Feb 6, 2020
39d52e0
:dromedary_camel: DRY up key validation logic
Feb 6, 2020
8b71875
:black_large_square: use invisible
Feb 6, 2020
f3dbfb9
use latest pkgs
Feb 11, 2020
e3a40c3
update package docs
Feb 11, 2020
df3d780
update docs; remove name, add title
Feb 11, 2020
84f8464
note title method
Feb 11, 2020
5bbba6e
:see_no_evil: need default app name
Feb 11, 2020
2aef1f3
:rotating_light: add integration tests
Feb 11, 2020
56904ba
fix ref for dcc
Feb 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions DESCRIPTION
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
Package: dash
Title: An Interface to the Dash Ecosystem for Authoring Reactive Web Applications
Version: 0.2.0
Version: 0.3.0
Authors@R: c(person("Chris", "Parmer", role = c("aut"), email = "chris@plot.ly"), person("Ryan Patrick", "Kyle", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-5829-9867"), email = "ryan@plot.ly"), person("Carson", "Sievert", role = c("aut"), comment = c(ORCID = "0000-0002-4958-2844")), person(family = "Plotly Technologies", role = "cph"))
Description: A framework for building analytical web applications, Dash offers a pleasant and productive development experience. No JavaScript required.
Depends:
R (>= 3.0.2)
Imports:
dashHtmlComponents (== 1.0.2),
Comment thread
rpkyle marked this conversation as resolved.
dashCoreComponents (== 1.6.0),
dashTable (== 4.5.1),
dashCoreComponents (== 1.8.0),
dashTable (== 4.6.0),
R6,
fiery (> 1.0.0),
routr (> 0.2.0),
Expand All@@ -32,8 +32,8 @@ Collate:
'print.R'
'internal.R'
Remotes: plotly/dash-html-components@55c3884,
Comment thread
rpkyle marked this conversation as resolved.
plotly/dash-core-components@c107e0f,
plotly/dash-table@3058bd5
plotly/dash-core-components@fc153b4,
plotly/dash-table@79d46ca
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Expand Down
2 changes: 1 addition & 1 deletion NAMESPACE
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,4 +27,4 @@ importFrom(routr,RouteStack)
importFrom(routr,ressource_route)
importFrom(stats,setNames)
importFrom(tools,file_ext)
importFrom(utils,getFromNamespace)
importFrom(utils,getFromNamespace)
175 changes: 154 additions & 21 deletions R/dash.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,7 @@
#' @usage Dash
#'
#' @section Constructor: Dash$new(
#' name = "dash",
#' name = NULL,
#' server = fiery::Fire$new(),
#' assets_folder = 'assets',
#' assets_url_path = '/assets',
Expand All@@ -24,7 +24,7 @@
#' @section Arguments:
#' \tabular{lll}{
#' `name` \tab \tab Character. The name of the Dash application (placed in the `<title>`
#' of the HTML page).\cr
#' of the HTML page). DEPRECATED; please use `index_string()` or `interpolate_index()` instead.\cr
#' `server` \tab \tab The web server used to power the application.
#' Must be a [fiery::Fire] object.\cr
#' `assets_folder` \tab \tab Character. A path, relative to the current working directory,
Expand DownExpand Up@@ -100,6 +100,9 @@
#' from the Dash backend. The latter may offer improved performance relative
#' to callbacks written in R.
#' }
#' \item{`title("dash")`}{
#' The title of the app. If no title is supplied, Dash for R will use 'dash'.
#' }
#' \item{`callback_context()`}{
#' The `callback_context` method permits retrieving the inputs which triggered
#' the firing of a given callback, and allows introspection of the input/state
Expand All@@ -114,7 +117,63 @@
#' 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)`}{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

#' The `index_string` method allows the specification of a custom index by changing
Comment thread
rpkyle marked this conversation as 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 elements
#' and return an error if a valid index is not defined. The following interpolation keys are
#' currently supported:
#' \describe{
#' \item{`{%metas%}`}{Optional - The registered meta tags.}
#' \item{`{%favicon%}`}{Optional - A favicon link tag if found in assets.}
#' \item{`{%css%}`}{Optional - Link tags to css resources.}
#' \item{`{%config%}`}{Required - Config generated by dash for the renderer.}
#' \item{`{%app_entry%}`}{Required - The container where dash react components are rendered.}
#' \item{`{%scripts%}`}{Required - Collected dependencies scripts tags.}
#' }
#' \describe{
#' \item{Example of a basic HTML index string:}{
#' \preformatted{
#' "<!DOCTYPE html>
#' <html>
#' <head>
#' \{\%meta_tags\%\}
#' <title>\{\{%css\%\}\}</title>
#' \{\%favicon\%\}
#' \{\%css_tags\%\}
#' </head>
#' <body>
#' \{\%app_entry\%\}
#' <footer>
#' \{\%config\%\}
#' \{\%scripts\%\}
#' </footer>
#' </body>
#' </html>"
#' }
#' }
#' }
#' }
#' \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:
#' \preformatted{
#' 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{...}{Named List. The unnamed arguments 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{
Expand DownExpand Up@@ -174,7 +233,7 @@ Dash <- R6::R6Class(
config = list(),

# i.e., the Dash$new() method
initialize = function(name = "dash",
initialize = function(name = NULL,
server = fiery::Fire$new(),
assets_folder = 'assets',
assets_url_path = '/assets',
Expand All@@ -191,13 +250,18 @@ Dash <- R6::R6Class(
suppress_callback_exceptions = FALSE) {

# argument type checking
assertthat::assert_that(is.character(name))
assertthat::assert_that(inherits(server, "Fire"))
assertthat::assert_that(is.logical(serve_locally))
assertthat::assert_that(is.logical(suppress_callback_exceptions))

# save relevant args as private fields
private$name <- name
if (!is.null(name)) {
warning(sprintf(
"The supplied application title, '%s', should be set using the title() method, or passed via index_string() or interpolate_index(); it has been ignored, and 'dash' will be used instead.",
name),
call. = FALSE
)
}
private$serve_locally <- serve_locally
private$eager_loading <- eager_loading
# remove leading and trailing slash(es) if present
Expand DownExpand Up@@ -763,11 +827,44 @@ Dash <- R6::R6Class(
sep="/")))
},

# ------------------------------------------------------------------------
# specify a custom index string
# ------------------------------------------------------------------------
index_string = function(string) {
private$custom_index <- validate_keys(string)
},
Comment thread
rpkyle marked this conversation as 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)
}

invisible(validate_keys(names(kwargs)))

private$template_index <- template
},

# ------------------------------------------------------------------------
# specify a custom title
# ------------------------------------------------------------------------
title = function(string = "dash") {
assertthat::assert_that(is.character(string))
private$name <- string
},

# ------------------------------------------------------------------------
# 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,
Expand DownExpand Up@@ -1266,6 +1363,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>{%title%}</title>
{%favicon%}
{%css_tags%}
</head>
<body>
{%app_entry%}
<footer>
{%config%}
{%scripts%}
</footer>
</body>
</html>", NA),
.index = NULL,

generateReloadHash = function() {
Expand DownExpand Up@@ -1434,13 +1549,32 @@ 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$name))
private$name <- 'dash'

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
Expand All@@ -1450,23 +1584,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
)
}
}
)
)
Expand Down
30 changes: 30 additions & 0 deletions R/utils.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -1270,3 +1270,33 @@ tryCompress <- function(request, response) {
}
return(response$compress())
}

interpolate_str <- function(index_template, ...) {
# This function takes an index string, along with
# user specified keys for the html keys of the index
# and sets the default values of the keys to the
# ones specified by the keys themselves, returning
# the custom index template.
template = index_template
kwargs <- list(...)

for (name in names(kwargs)) {
key = paste0('\\{', name, '\\}')

template = sub(key, kwargs[[name]], template)
}
return(template)
}

validate_keys <- function(string) {
required_keys <- c("app_entry", "config", "scripts")

keys_present <- vapply(required_keys, function(x) grepl(x, string), logical(1))

if (!all(keys_present)) {
stop(sprintf("Did you forget to include %s in your index string?",
paste(names(keys_present[keys_present==FALSE]), collapse = ", ")))
} else {
return(string)
}
}
2 changes: 1 addition & 1 deletion README.md
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
[![CircleCI](https://circleci.com/gh/plotly/dashR/tree/dev.svg?style=svg)](https://circleci.com/gh/plotly/dashR/tree/dev)
[![CircleCI](https://circleci.com/gh/plotly/dashR/tree/master.svg?style=svg)](https://circleci.com/gh/plotly/dashR/tree/master)
[![GitHub](https://img.shields.io/github/license/plotly/dashR.svg?color=dark-green)](https://github.com/plotly/dashR/blob/master/LICENSE)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/y/plotly/dashR.svg?color=dark-green)](https://github.com/plotly/dashR/graphs/contributors)

Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Support for index page templating by HammadTheOne · Pull Request #168 · plotly/dashR · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f6c13a9
Dash for R v0.2.0 (#162)
rpkyle Jan 4, 2020
f81fcb5
Update README.md
rpkyle Jan 5, 2020
a58d4f2
Added initial implementation of index customization with strings
HammadTheOne Jan 9, 2020
4d72243
Fixed issue with `collect_assets` being undefined
HammadTheOne Jan 10, 2020
30251cf
Added description and details.
HammadTheOne Jan 10, 2020
3346a93
Added description
HammadTheOne Jan 14, 2020
2e58b37
Added error messages and warnings.
HammadTheOne Jan 14, 2020
0984660
Merge branch 'dev' into 42-index-page-templating
HammadTheOne Jan 14, 2020
3aa0f50
Updated version to 0.3.0
HammadTheOne Jan 16, 2020
a2410d5
Added CRLF
HammadTheOne Jan 16, 2020
a158a37
Updated environment variable names to `dev` versions.
HammadTheOne Jan 17, 2020
1138e4c
Improved error message function, made parity changes for index keys.
HammadTheOne Jan 17, 2020
fd67f8a
Added available keys to description.
HammadTheOne Jan 17, 2020
17a61d1
Parity changes to `app_entry` and `config` keys
HammadTheOne Jan 17, 2020
13ebec4
Cleaned up description.
HammadTheOne Jan 17, 2020
ab54aa0
Added `interpolate_str` helper function to `utils.R`
HammadTheOne Jan 17, 2020
ce4a8b6
Changes to default index, consolidating `_dash-config`
HammadTheOne Jan 17, 2020
036e4e5
Added template index and logic for choosing correct index.
HammadTheOne Jan 19, 2020
09b0851
Added description for `interpolate_index`.
HammadTheOne Jan 19, 2020
4023b67
Updated glue arguments in `index_string` method, added example index.
HammadTheOne Jan 27, 2020
8e98370
Update to `interpolate_index` to reflect changes to `index_string`.
HammadTheOne Jan 27, 2020
0ce3158
Bugfix, referenced correct private variable.
HammadTheOne Jan 27, 2020
7fd1ebe
Update R/dash.R
rpkyle Feb 6, 2020
a0c2f7e
:hocho: cat(template)
Feb 6, 2020
5ae7549
:camel: make concise
Feb 6, 2020
79b0faa
replace = with <-
Feb 6, 2020
39d52e0
:dromedary_camel: DRY up key validation logic
Feb 6, 2020
8b71875
:black_large_square: use invisible
Feb 6, 2020
f3dbfb9
use latest pkgs
Feb 11, 2020
e3a40c3
update package docs
Feb 11, 2020
df3d780
update docs; remove name, add title
Feb 11, 2020
84f8464
note title method
Feb 11, 2020
5bbba6e
:see_no_evil: need default app name
Feb 11, 2020
2aef1f3
:rotating_light: add integration tests
Feb 11, 2020
56904ba
fix ref for dcc
Feb 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions DESCRIPTION
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
Package: dash
Title: An Interface to the Dash Ecosystem for Authoring Reactive Web Applications
Version: 0.2.0
Version: 0.3.0
Authors@R: c(person("Chris", "Parmer", role = c("aut"), email = "chris@plot.ly"), person("Ryan Patrick", "Kyle", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-5829-9867"), email = "ryan@plot.ly"), person("Carson", "Sievert", role = c("aut"), comment = c(ORCID = "0000-0002-4958-2844")), person(family = "Plotly Technologies", role = "cph"))
Description: A framework for building analytical web applications, Dash offers a pleasant and productive development experience. No JavaScript required.
Depends:
R (>= 3.0.2)
Imports:
dashHtmlComponents (== 1.0.2),
Comment thread
rpkyle marked this conversation as resolved.
dashCoreComponents (== 1.6.0),
dashTable (== 4.5.1),
dashCoreComponents (== 1.8.0),
dashTable (== 4.6.0),
R6,
fiery (> 1.0.0),
routr (> 0.2.0),
Expand All@@ -32,8 +32,8 @@ Collate:
'print.R'
'internal.R'
Remotes: plotly/dash-html-components@55c3884,
Comment thread
rpkyle marked this conversation as resolved.
plotly/dash-core-components@c107e0f,
plotly/dash-table@3058bd5
plotly/dash-core-components@fc153b4,
plotly/dash-table@79d46ca
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Expand Down
2 changes: 1 addition & 1 deletion NAMESPACE
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,4 +27,4 @@ importFrom(routr,RouteStack)
importFrom(routr,ressource_route)
importFrom(stats,setNames)
importFrom(tools,file_ext)
importFrom(utils,getFromNamespace)
importFrom(utils,getFromNamespace)
175 changes: 154 additions & 21 deletions R/dash.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,7 @@
#' @usage Dash
#'
#' @section Constructor: Dash$new(
#' name = "dash",
#' name = NULL,
#' server = fiery::Fire$new(),
#' assets_folder = 'assets',
#' assets_url_path = '/assets',
Expand All@@ -24,7 +24,7 @@
#' @section Arguments:
#' \tabular{lll}{
#' `name` \tab \tab Character. The name of the Dash application (placed in the `<title>`
#' of the HTML page).\cr
#' of the HTML page). DEPRECATED; please use `index_string()` or `interpolate_index()` instead.\cr
#' `server` \tab \tab The web server used to power the application.
#' Must be a [fiery::Fire] object.\cr
#' `assets_folder` \tab \tab Character. A path, relative to the current working directory,
Expand DownExpand Up@@ -100,6 +100,9 @@
#' from the Dash backend. The latter may offer improved performance relative
#' to callbacks written in R.
#' }
#' \item{`title("dash")`}{
#' The title of the app. If no title is supplied, Dash for R will use 'dash'.
#' }
#' \item{`callback_context()`}{
#' The `callback_context` method permits retrieving the inputs which triggered
#' the firing of a given callback, and allows introspection of the input/state
Expand All@@ -114,7 +117,63 @@
#' 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)`}{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

#' The `index_string` method allows the specification of a custom index by changing
Comment thread
rpkyle marked this conversation as 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 elements
#' and return an error if a valid index is not defined. The following interpolation keys are
#' currently supported:
#' \describe{
#' \item{`{%metas%}`}{Optional - The registered meta tags.}
#' \item{`{%favicon%}`}{Optional - A favicon link tag if found in assets.}
#' \item{`{%css%}`}{Optional - Link tags to css resources.}
#' \item{`{%config%}`}{Required - Config generated by dash for the renderer.}
#' \item{`{%app_entry%}`}{Required - The container where dash react components are rendered.}
#' \item{`{%scripts%}`}{Required - Collected dependencies scripts tags.}
#' }
#' \describe{
#' \item{Example of a basic HTML index string:}{
#' \preformatted{
#' "<!DOCTYPE html>
#' <html>
#' <head>
#' \{\%meta_tags\%\}
#' <title>\{\{%css\%\}\}</title>
#' \{\%favicon\%\}
#' \{\%css_tags\%\}
#' </head>
#' <body>
#' \{\%app_entry\%\}
#' <footer>
#' \{\%config\%\}
#' \{\%scripts\%\}
#' </footer>
#' </body>
#' </html>"
#' }
#' }
#' }
#' }
#' \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:
#' \preformatted{
#' 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{...}{Named List. The unnamed arguments 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{
Expand DownExpand Up@@ -174,7 +233,7 @@ Dash <- R6::R6Class(
config = list(),

# i.e., the Dash$new() method
initialize = function(name = "dash",
initialize = function(name = NULL,
server = fiery::Fire$new(),
assets_folder = 'assets',
assets_url_path = '/assets',
Expand All@@ -191,13 +250,18 @@ Dash <- R6::R6Class(
suppress_callback_exceptions = FALSE) {

# argument type checking
assertthat::assert_that(is.character(name))
assertthat::assert_that(inherits(server, "Fire"))
assertthat::assert_that(is.logical(serve_locally))
assertthat::assert_that(is.logical(suppress_callback_exceptions))

# save relevant args as private fields
private$name <- name
if (!is.null(name)) {
warning(sprintf(
"The supplied application title, '%s', should be set using the title() method, or passed via index_string() or interpolate_index(); it has been ignored, and 'dash' will be used instead.",
name),
call. = FALSE
)
}
private$serve_locally <- serve_locally
private$eager_loading <- eager_loading
# remove leading and trailing slash(es) if present
Expand DownExpand Up@@ -763,11 +827,44 @@ Dash <- R6::R6Class(
sep="/")))
},

# ------------------------------------------------------------------------
# specify a custom index string
# ------------------------------------------------------------------------
index_string = function(string) {
private$custom_index <- validate_keys(string)
},
Comment thread
rpkyle marked this conversation as 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)
}

invisible(validate_keys(names(kwargs)))

private$template_index <- template
},

# ------------------------------------------------------------------------
# specify a custom title
# ------------------------------------------------------------------------
title = function(string = "dash") {
assertthat::assert_that(is.character(string))
private$name <- string
},

# ------------------------------------------------------------------------
# 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,
Expand DownExpand Up@@ -1266,6 +1363,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>{%title%}</title>
{%favicon%}
{%css_tags%}
</head>
<body>
{%app_entry%}
<footer>
{%config%}
{%scripts%}
</footer>
</body>
</html>", NA),
.index = NULL,

generateReloadHash = function() {
Expand DownExpand Up@@ -1434,13 +1549,32 @@ 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$name))
private$name <- 'dash'

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
Expand All@@ -1450,23 +1584,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
)
}
}
)
)
Expand Down
30 changes: 30 additions & 0 deletions R/utils.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -1270,3 +1270,33 @@ tryCompress <- function(request, response) {
}
return(response$compress())
}

interpolate_str <- function(index_template, ...) {
# This function takes an index string, along with
# user specified keys for the html keys of the index
# and sets the default values of the keys to the
# ones specified by the keys themselves, returning
# the custom index template.
template = index_template
kwargs <- list(...)

for (name in names(kwargs)) {
key = paste0('\\{', name, '\\}')

template = sub(key, kwargs[[name]], template)
}
return(template)
}

validate_keys <- function(string) {
required_keys <- c("app_entry", "config", "scripts")

keys_present <- vapply(required_keys, function(x) grepl(x, string), logical(1))

if (!all(keys_present)) {
stop(sprintf("Did you forget to include %s in your index string?",
paste(names(keys_present[keys_present==FALSE]), collapse = ", ")))
} else {
return(string)
}
}
2 changes: 1 addition & 1 deletion README.md
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
[![CircleCI](https://circleci.com/gh/plotly/dashR/tree/dev.svg?style=svg)](https://circleci.com/gh/plotly/dashR/tree/dev)
[![CircleCI](https://circleci.com/gh/plotly/dashR/tree/master.svg?style=svg)](https://circleci.com/gh/plotly/dashR/tree/master)
[![GitHub](https://img.shields.io/github/license/plotly/dashR.svg?color=dark-green)](https://github.com/plotly/dashR/blob/master/LICENSE)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/y/plotly/dashR.svg?color=dark-green)](https://github.com/plotly/dashR/graphs/contributors)

Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Support for index page templating by HammadTheOne · Pull Request #168 · plotly/dashR · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f6c13a9
Dash for R v0.2.0 (#162)
rpkyle Jan 4, 2020
f81fcb5
Update README.md
rpkyle Jan 5, 2020
a58d4f2
Added initial implementation of index customization with strings
HammadTheOne Jan 9, 2020
4d72243
Fixed issue with `collect_assets` being undefined
HammadTheOne Jan 10, 2020
30251cf
Added description and details.
HammadTheOne Jan 10, 2020
3346a93
Added description
HammadTheOne Jan 14, 2020
2e58b37
Added error messages and warnings.
HammadTheOne Jan 14, 2020
0984660
Merge branch 'dev' into 42-index-page-templating
HammadTheOne Jan 14, 2020
3aa0f50
Updated version to 0.3.0
HammadTheOne Jan 16, 2020
a2410d5
Added CRLF
HammadTheOne Jan 16, 2020
a158a37
Updated environment variable names to `dev` versions.
HammadTheOne Jan 17, 2020
1138e4c
Improved error message function, made parity changes for index keys.
HammadTheOne Jan 17, 2020
fd67f8a
Added available keys to description.
HammadTheOne Jan 17, 2020
17a61d1
Parity changes to `app_entry` and `config` keys
HammadTheOne Jan 17, 2020
13ebec4
Cleaned up description.
HammadTheOne Jan 17, 2020
ab54aa0
Added `interpolate_str` helper function to `utils.R`
HammadTheOne Jan 17, 2020
ce4a8b6
Changes to default index, consolidating `_dash-config`
HammadTheOne Jan 17, 2020
036e4e5
Added template index and logic for choosing correct index.
HammadTheOne Jan 19, 2020
09b0851
Added description for `interpolate_index`.
HammadTheOne Jan 19, 2020
4023b67
Updated glue arguments in `index_string` method, added example index.
HammadTheOne Jan 27, 2020
8e98370
Update to `interpolate_index` to reflect changes to `index_string`.
HammadTheOne Jan 27, 2020
0ce3158
Bugfix, referenced correct private variable.
HammadTheOne Jan 27, 2020
7fd1ebe
Update R/dash.R
rpkyle Feb 6, 2020
a0c2f7e
:hocho: cat(template)
Feb 6, 2020
5ae7549
:camel: make concise
Feb 6, 2020
79b0faa
replace = with <-
Feb 6, 2020
39d52e0
:dromedary_camel: DRY up key validation logic
Feb 6, 2020
8b71875
:black_large_square: use invisible
Feb 6, 2020
f3dbfb9
use latest pkgs
Feb 11, 2020
e3a40c3
update package docs
Feb 11, 2020
df3d780
update docs; remove name, add title
Feb 11, 2020
84f8464
note title method
Feb 11, 2020
5bbba6e
:see_no_evil: need default app name
Feb 11, 2020
2aef1f3
:rotating_light: add integration tests
Feb 11, 2020
56904ba
fix ref for dcc
Feb 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions DESCRIPTION
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
Package: dash
Title: An Interface to the Dash Ecosystem for Authoring Reactive Web Applications
Version: 0.2.0
Version: 0.3.0
Authors@R: c(person("Chris", "Parmer", role = c("aut"), email = "chris@plot.ly"), person("Ryan Patrick", "Kyle", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-5829-9867"), email = "ryan@plot.ly"), person("Carson", "Sievert", role = c("aut"), comment = c(ORCID = "0000-0002-4958-2844")), person(family = "Plotly Technologies", role = "cph"))
Description: A framework for building analytical web applications, Dash offers a pleasant and productive development experience. No JavaScript required.
Depends:
R (>= 3.0.2)
Imports:
dashHtmlComponents (== 1.0.2),
Comment thread
rpkyle marked this conversation as resolved.
dashCoreComponents (== 1.6.0),
dashTable (== 4.5.1),
dashCoreComponents (== 1.8.0),
dashTable (== 4.6.0),
R6,
fiery (> 1.0.0),
routr (> 0.2.0),
Expand All@@ -32,8 +32,8 @@ Collate:
'print.R'
'internal.R'
Remotes: plotly/dash-html-components@55c3884,
Comment thread
rpkyle marked this conversation as resolved.
plotly/dash-core-components@c107e0f,
plotly/dash-table@3058bd5
plotly/dash-core-components@fc153b4,
plotly/dash-table@79d46ca
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Expand Down
2 changes: 1 addition & 1 deletion NAMESPACE
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,4 +27,4 @@ importFrom(routr,RouteStack)
importFrom(routr,ressource_route)
importFrom(stats,setNames)
importFrom(tools,file_ext)
importFrom(utils,getFromNamespace)
importFrom(utils,getFromNamespace)
175 changes: 154 additions & 21 deletions R/dash.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,7 @@
#' @usage Dash
#'
#' @section Constructor: Dash$new(
#' name = "dash",
#' name = NULL,
#' server = fiery::Fire$new(),
#' assets_folder = 'assets',
#' assets_url_path = '/assets',
Expand All@@ -24,7 +24,7 @@
#' @section Arguments:
#' \tabular{lll}{
#' `name` \tab \tab Character. The name of the Dash application (placed in the `<title>`
#' of the HTML page).\cr
#' of the HTML page). DEPRECATED; please use `index_string()` or `interpolate_index()` instead.\cr
#' `server` \tab \tab The web server used to power the application.
#' Must be a [fiery::Fire] object.\cr
#' `assets_folder` \tab \tab Character. A path, relative to the current working directory,
Expand DownExpand Up@@ -100,6 +100,9 @@
#' from the Dash backend. The latter may offer improved performance relative
#' to callbacks written in R.
#' }
#' \item{`title("dash")`}{
#' The title of the app. If no title is supplied, Dash for R will use 'dash'.
#' }
#' \item{`callback_context()`}{
#' The `callback_context` method permits retrieving the inputs which triggered
#' the firing of a given callback, and allows introspection of the input/state
Expand All@@ -114,7 +117,63 @@
#' 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)`}{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

#' The `index_string` method allows the specification of a custom index by changing
Comment thread
rpkyle marked this conversation as 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 elements
#' and return an error if a valid index is not defined. The following interpolation keys are
#' currently supported:
#' \describe{
#' \item{`{%metas%}`}{Optional - The registered meta tags.}
#' \item{`{%favicon%}`}{Optional - A favicon link tag if found in assets.}
#' \item{`{%css%}`}{Optional - Link tags to css resources.}
#' \item{`{%config%}`}{Required - Config generated by dash for the renderer.}
#' \item{`{%app_entry%}`}{Required - The container where dash react components are rendered.}
#' \item{`{%scripts%}`}{Required - Collected dependencies scripts tags.}
#' }
#' \describe{
#' \item{Example of a basic HTML index string:}{
#' \preformatted{
#' "<!DOCTYPE html>
#' <html>
#' <head>
#' \{\%meta_tags\%\}
#' <title>\{\{%css\%\}\}</title>
#' \{\%favicon\%\}
#' \{\%css_tags\%\}
#' </head>
#' <body>
#' \{\%app_entry\%\}
#' <footer>
#' \{\%config\%\}
#' \{\%scripts\%\}
#' </footer>
#' </body>
#' </html>"
#' }
#' }
#' }
#' }
#' \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:
#' \preformatted{
#' 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{...}{Named List. The unnamed arguments 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{
Expand DownExpand Up@@ -174,7 +233,7 @@ Dash <- R6::R6Class(
config = list(),

# i.e., the Dash$new() method
initialize = function(name = "dash",
initialize = function(name = NULL,
server = fiery::Fire$new(),
assets_folder = 'assets',
assets_url_path = '/assets',
Expand All@@ -191,13 +250,18 @@ Dash <- R6::R6Class(
suppress_callback_exceptions = FALSE) {

# argument type checking
assertthat::assert_that(is.character(name))
assertthat::assert_that(inherits(server, "Fire"))
assertthat::assert_that(is.logical(serve_locally))
assertthat::assert_that(is.logical(suppress_callback_exceptions))

# save relevant args as private fields
private$name <- name
if (!is.null(name)) {
warning(sprintf(
"The supplied application title, '%s', should be set using the title() method, or passed via index_string() or interpolate_index(); it has been ignored, and 'dash' will be used instead.",
name),
call. = FALSE
)
}
private$serve_locally <- serve_locally
private$eager_loading <- eager_loading
# remove leading and trailing slash(es) if present
Expand DownExpand Up@@ -763,11 +827,44 @@ Dash <- R6::R6Class(
sep="/")))
},

# ------------------------------------------------------------------------
# specify a custom index string
# ------------------------------------------------------------------------
index_string = function(string) {
private$custom_index <- validate_keys(string)
},
Comment thread
rpkyle marked this conversation as 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)
}

invisible(validate_keys(names(kwargs)))

private$template_index <- template
},

# ------------------------------------------------------------------------
# specify a custom title
# ------------------------------------------------------------------------
title = function(string = "dash") {
assertthat::assert_that(is.character(string))
private$name <- string
},

# ------------------------------------------------------------------------
# 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,
Expand DownExpand Up@@ -1266,6 +1363,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>{%title%}</title>
{%favicon%}
{%css_tags%}
</head>
<body>
{%app_entry%}
<footer>
{%config%}
{%scripts%}
</footer>
</body>
</html>", NA),
.index = NULL,

generateReloadHash = function() {
Expand DownExpand Up@@ -1434,13 +1549,32 @@ 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$name))
private$name <- 'dash'

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
Expand All@@ -1450,23 +1584,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
)
}
}
)
)
Expand Down
30 changes: 30 additions & 0 deletions R/utils.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -1270,3 +1270,33 @@ tryCompress <- function(request, response) {
}
return(response$compress())
}

interpolate_str <- function(index_template, ...) {
# This function takes an index string, along with
# user specified keys for the html keys of the index
# and sets the default values of the keys to the
# ones specified by the keys themselves, returning
# the custom index template.
template = index_template
kwargs <- list(...)

for (name in names(kwargs)) {
key = paste0('\\{', name, '\\}')

template = sub(key, kwargs[[name]], template)
}
return(template)
}

validate_keys <- function(string) {
required_keys <- c("app_entry", "config", "scripts")

keys_present <- vapply(required_keys, function(x) grepl(x, string), logical(1))

if (!all(keys_present)) {
stop(sprintf("Did you forget to include %s in your index string?",
paste(names(keys_present[keys_present==FALSE]), collapse = ", ")))
} else {
return(string)
}
}
2 changes: 1 addition & 1 deletion README.md
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
[![CircleCI](https://circleci.com/gh/plotly/dashR/tree/dev.svg?style=svg)](https://circleci.com/gh/plotly/dashR/tree/dev)
[![CircleCI](https://circleci.com/gh/plotly/dashR/tree/master.svg?style=svg)](https://circleci.com/gh/plotly/dashR/tree/master)
[![GitHub](https://img.shields.io/github/license/plotly/dashR.svg?color=dark-green)](https://github.com/plotly/dashR/blob/master/LICENSE)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/y/plotly/dashR.svg?color=dark-green)](https://github.com/plotly/dashR/graphs/contributors)

Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Support for index page templating by HammadTheOne · Pull Request #168 · plotly/dashR · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f6c13a9
Dash for R v0.2.0 (#162)
rpkyle Jan 4, 2020
f81fcb5
Update README.md
rpkyle Jan 5, 2020
a58d4f2
Added initial implementation of index customization with strings
HammadTheOne Jan 9, 2020
4d72243
Fixed issue with `collect_assets` being undefined
HammadTheOne Jan 10, 2020
30251cf
Added description and details.
HammadTheOne Jan 10, 2020
3346a93
Added description
HammadTheOne Jan 14, 2020
2e58b37
Added error messages and warnings.
HammadTheOne Jan 14, 2020
0984660
Merge branch 'dev' into 42-index-page-templating
HammadTheOne Jan 14, 2020
3aa0f50
Updated version to 0.3.0
HammadTheOne Jan 16, 2020
a2410d5
Added CRLF
HammadTheOne Jan 16, 2020
a158a37
Updated environment variable names to `dev` versions.
HammadTheOne Jan 17, 2020
1138e4c
Improved error message function, made parity changes for index keys.
HammadTheOne Jan 17, 2020
fd67f8a
Added available keys to description.
HammadTheOne Jan 17, 2020
17a61d1
Parity changes to `app_entry` and `config` keys
HammadTheOne Jan 17, 2020
13ebec4
Cleaned up description.
HammadTheOne Jan 17, 2020
ab54aa0
Added `interpolate_str` helper function to `utils.R`
HammadTheOne Jan 17, 2020
ce4a8b6
Changes to default index, consolidating `_dash-config`
HammadTheOne Jan 17, 2020
036e4e5
Added template index and logic for choosing correct index.
HammadTheOne Jan 19, 2020
09b0851
Added description for `interpolate_index`.
HammadTheOne Jan 19, 2020
4023b67
Updated glue arguments in `index_string` method, added example index.
HammadTheOne Jan 27, 2020
8e98370
Update to `interpolate_index` to reflect changes to `index_string`.
HammadTheOne Jan 27, 2020
0ce3158
Bugfix, referenced correct private variable.
HammadTheOne Jan 27, 2020
7fd1ebe
Update R/dash.R
rpkyle Feb 6, 2020
a0c2f7e
:hocho: cat(template)
Feb 6, 2020
5ae7549
:camel: make concise
Feb 6, 2020
79b0faa
replace = with <-
Feb 6, 2020
39d52e0
:dromedary_camel: DRY up key validation logic
Feb 6, 2020
8b71875
:black_large_square: use invisible
Feb 6, 2020
f3dbfb9
use latest pkgs
Feb 11, 2020
e3a40c3
update package docs
Feb 11, 2020
df3d780
update docs; remove name, add title
Feb 11, 2020
84f8464
note title method
Feb 11, 2020
5bbba6e
:see_no_evil: need default app name
Feb 11, 2020
2aef1f3
:rotating_light: add integration tests
Feb 11, 2020
56904ba
fix ref for dcc
Feb 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions DESCRIPTION
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
Package: dash
Title: An Interface to the Dash Ecosystem for Authoring Reactive Web Applications
Version: 0.2.0
Version: 0.3.0
Authors@R: c(person("Chris", "Parmer", role = c("aut"), email = "chris@plot.ly"), person("Ryan Patrick", "Kyle", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-5829-9867"), email = "ryan@plot.ly"), person("Carson", "Sievert", role = c("aut"), comment = c(ORCID = "0000-0002-4958-2844")), person(family = "Plotly Technologies", role = "cph"))
Description: A framework for building analytical web applications, Dash offers a pleasant and productive development experience. No JavaScript required.
Depends:
R (>= 3.0.2)
Imports:
dashHtmlComponents (== 1.0.2),
Comment thread
rpkyle marked this conversation as resolved.
dashCoreComponents (== 1.6.0),
dashTable (== 4.5.1),
dashCoreComponents (== 1.8.0),
dashTable (== 4.6.0),
R6,
fiery (> 1.0.0),
routr (> 0.2.0),
Expand All@@ -32,8 +32,8 @@ Collate:
'print.R'
'internal.R'
Remotes: plotly/dash-html-components@55c3884,
Comment thread
rpkyle marked this conversation as resolved.
plotly/dash-core-components@c107e0f,
plotly/dash-table@3058bd5
plotly/dash-core-components@fc153b4,
plotly/dash-table@79d46ca
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Expand Down
2 changes: 1 addition & 1 deletion NAMESPACE
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,4 +27,4 @@ importFrom(routr,RouteStack)
importFrom(routr,ressource_route)
importFrom(stats,setNames)
importFrom(tools,file_ext)
importFrom(utils,getFromNamespace)
importFrom(utils,getFromNamespace)
175 changes: 154 additions & 21 deletions R/dash.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,7 @@
#' @usage Dash
#'
#' @section Constructor: Dash$new(
#' name = "dash",
#' name = NULL,
#' server = fiery::Fire$new(),
#' assets_folder = 'assets',
#' assets_url_path = '/assets',
Expand All@@ -24,7 +24,7 @@
#' @section Arguments:
#' \tabular{lll}{
#' `name` \tab \tab Character. The name of the Dash application (placed in the `<title>`
#' of the HTML page).\cr
#' of the HTML page). DEPRECATED; please use `index_string()` or `interpolate_index()` instead.\cr
#' `server` \tab \tab The web server used to power the application.
#' Must be a [fiery::Fire] object.\cr
#' `assets_folder` \tab \tab Character. A path, relative to the current working directory,
Expand DownExpand Up@@ -100,6 +100,9 @@
#' from the Dash backend. The latter may offer improved performance relative
#' to callbacks written in R.
#' }
#' \item{`title("dash")`}{
#' The title of the app. If no title is supplied, Dash for R will use 'dash'.
#' }
#' \item{`callback_context()`}{
#' The `callback_context` method permits retrieving the inputs which triggered
#' the firing of a given callback, and allows introspection of the input/state
Expand All@@ -114,7 +117,63 @@
#' 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)`}{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

#' The `index_string` method allows the specification of a custom index by changing
Comment thread
rpkyle marked this conversation as 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 elements
#' and return an error if a valid index is not defined. The following interpolation keys are
#' currently supported:
#' \describe{
#' \item{`{%metas%}`}{Optional - The registered meta tags.}
#' \item{`{%favicon%}`}{Optional - A favicon link tag if found in assets.}
#' \item{`{%css%}`}{Optional - Link tags to css resources.}
#' \item{`{%config%}`}{Required - Config generated by dash for the renderer.}
#' \item{`{%app_entry%}`}{Required - The container where dash react components are rendered.}
#' \item{`{%scripts%}`}{Required - Collected dependencies scripts tags.}
#' }
#' \describe{
#' \item{Example of a basic HTML index string:}{
#' \preformatted{
#' "<!DOCTYPE html>
#' <html>
#' <head>
#' \{\%meta_tags\%\}
#' <title>\{\{%css\%\}\}</title>
#' \{\%favicon\%\}
#' \{\%css_tags\%\}
#' </head>
#' <body>
#' \{\%app_entry\%\}
#' <footer>
#' \{\%config\%\}
#' \{\%scripts\%\}
#' </footer>
#' </body>
#' </html>"
#' }
#' }
#' }
#' }
#' \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:
#' \preformatted{
#' 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{...}{Named List. The unnamed arguments 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{
Expand DownExpand Up@@ -174,7 +233,7 @@ Dash <- R6::R6Class(
config = list(),

# i.e., the Dash$new() method
initialize = function(name = "dash",
initialize = function(name = NULL,
server = fiery::Fire$new(),
assets_folder = 'assets',
assets_url_path = '/assets',
Expand All@@ -191,13 +250,18 @@ Dash <- R6::R6Class(
suppress_callback_exceptions = FALSE) {

# argument type checking
assertthat::assert_that(is.character(name))
assertthat::assert_that(inherits(server, "Fire"))
assertthat::assert_that(is.logical(serve_locally))
assertthat::assert_that(is.logical(suppress_callback_exceptions))

# save relevant args as private fields
private$name <- name
if (!is.null(name)) {
warning(sprintf(
"The supplied application title, '%s', should be set using the title() method, or passed via index_string() or interpolate_index(); it has been ignored, and 'dash' will be used instead.",
name),
call. = FALSE
)
}
private$serve_locally <- serve_locally
private$eager_loading <- eager_loading
# remove leading and trailing slash(es) if present
Expand DownExpand Up@@ -763,11 +827,44 @@ Dash <- R6::R6Class(
sep="/")))
},

# ------------------------------------------------------------------------
# specify a custom index string
# ------------------------------------------------------------------------
index_string = function(string) {
private$custom_index <- validate_keys(string)
},
Comment thread
rpkyle marked this conversation as 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)
}

invisible(validate_keys(names(kwargs)))

private$template_index <- template
},

# ------------------------------------------------------------------------
# specify a custom title
# ------------------------------------------------------------------------
title = function(string = "dash") {
assertthat::assert_that(is.character(string))
private$name <- string
},

# ------------------------------------------------------------------------
# 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,
Expand DownExpand Up@@ -1266,6 +1363,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>{%title%}</title>
{%favicon%}
{%css_tags%}
</head>
<body>
{%app_entry%}
<footer>
{%config%}
{%scripts%}
</footer>
</body>
</html>", NA),
.index = NULL,

generateReloadHash = function() {
Expand DownExpand Up@@ -1434,13 +1549,32 @@ 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$name))
private$name <- 'dash'

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
Expand All@@ -1450,23 +1584,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
)
}
}
)
)
Expand Down
30 changes: 30 additions & 0 deletions R/utils.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -1270,3 +1270,33 @@ tryCompress <- function(request, response) {
}
return(response$compress())
}

interpolate_str <- function(index_template, ...) {
# This function takes an index string, along with
# user specified keys for the html keys of the index
# and sets the default values of the keys to the
# ones specified by the keys themselves, returning
# the custom index template.
template = index_template
kwargs <- list(...)

for (name in names(kwargs)) {
key = paste0('\\{', name, '\\}')

template = sub(key, kwargs[[name]], template)
}
return(template)
}

validate_keys <- function(string) {
required_keys <- c("app_entry", "config", "scripts")

keys_present <- vapply(required_keys, function(x) grepl(x, string), logical(1))

if (!all(keys_present)) {
stop(sprintf("Did you forget to include %s in your index string?",
paste(names(keys_present[keys_present==FALSE]), collapse = ", ")))
} else {
return(string)
}
}
2 changes: 1 addition & 1 deletion README.md
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
[![CircleCI](https://circleci.com/gh/plotly/dashR/tree/dev.svg?style=svg)](https://circleci.com/gh/plotly/dashR/tree/dev)
[![CircleCI](https://circleci.com/gh/plotly/dashR/tree/master.svg?style=svg)](https://circleci.com/gh/plotly/dashR/tree/master)
[![GitHub](https://img.shields.io/github/license/plotly/dashR.svg?color=dark-green)](https://github.com/plotly/dashR/blob/master/LICENSE)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/y/plotly/dashR.svg?color=dark-green)](https://github.com/plotly/dashR/graphs/contributors)

Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Support for index page templating by HammadTheOne · Pull Request #168 · plotly/dashR · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f6c13a9
Dash for R v0.2.0 (#162)
rpkyle Jan 4, 2020
f81fcb5
Update README.md
rpkyle Jan 5, 2020
a58d4f2
Added initial implementation of index customization with strings
HammadTheOne Jan 9, 2020
4d72243
Fixed issue with `collect_assets` being undefined
HammadTheOne Jan 10, 2020
30251cf
Added description and details.
HammadTheOne Jan 10, 2020
3346a93
Added description
HammadTheOne Jan 14, 2020
2e58b37
Added error messages and warnings.
HammadTheOne Jan 14, 2020
0984660
Merge branch 'dev' into 42-index-page-templating
HammadTheOne Jan 14, 2020
3aa0f50
Updated version to 0.3.0
HammadTheOne Jan 16, 2020
a2410d5
Added CRLF
HammadTheOne Jan 16, 2020
a158a37
Updated environment variable names to `dev` versions.
HammadTheOne Jan 17, 2020
1138e4c
Improved error message function, made parity changes for index keys.
HammadTheOne Jan 17, 2020
fd67f8a
Added available keys to description.
HammadTheOne Jan 17, 2020
17a61d1
Parity changes to `app_entry` and `config` keys
HammadTheOne Jan 17, 2020
13ebec4
Cleaned up description.
HammadTheOne Jan 17, 2020
ab54aa0
Added `interpolate_str` helper function to `utils.R`
HammadTheOne Jan 17, 2020
ce4a8b6
Changes to default index, consolidating `_dash-config`
HammadTheOne Jan 17, 2020
036e4e5
Added template index and logic for choosing correct index.
HammadTheOne Jan 19, 2020
09b0851
Added description for `interpolate_index`.
HammadTheOne Jan 19, 2020
4023b67
Updated glue arguments in `index_string` method, added example index.
HammadTheOne Jan 27, 2020
8e98370
Update to `interpolate_index` to reflect changes to `index_string`.
HammadTheOne Jan 27, 2020
0ce3158
Bugfix, referenced correct private variable.
HammadTheOne Jan 27, 2020
7fd1ebe
Update R/dash.R
rpkyle Feb 6, 2020
a0c2f7e
:hocho: cat(template)
Feb 6, 2020
5ae7549
:camel: make concise
Feb 6, 2020
79b0faa
replace = with <-
Feb 6, 2020
39d52e0
:dromedary_camel: DRY up key validation logic
Feb 6, 2020
8b71875
:black_large_square: use invisible
Feb 6, 2020
f3dbfb9
use latest pkgs
Feb 11, 2020
e3a40c3
update package docs
Feb 11, 2020
df3d780
update docs; remove name, add title
Feb 11, 2020
84f8464
note title method
Feb 11, 2020
5bbba6e
:see_no_evil: need default app name
Feb 11, 2020
2aef1f3
:rotating_light: add integration tests
Feb 11, 2020
56904ba
fix ref for dcc
Feb 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions DESCRIPTION
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
Package: dash
Title: An Interface to the Dash Ecosystem for Authoring Reactive Web Applications
Version: 0.2.0
Version: 0.3.0
Authors@R: c(person("Chris", "Parmer", role = c("aut"), email = "chris@plot.ly"), person("Ryan Patrick", "Kyle", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-5829-9867"), email = "ryan@plot.ly"), person("Carson", "Sievert", role = c("aut"), comment = c(ORCID = "0000-0002-4958-2844")), person(family = "Plotly Technologies", role = "cph"))
Description: A framework for building analytical web applications, Dash offers a pleasant and productive development experience. No JavaScript required.
Depends:
R (>= 3.0.2)
Imports:
dashHtmlComponents (== 1.0.2),
Comment thread
rpkyle marked this conversation as resolved.
dashCoreComponents (== 1.6.0),
dashTable (== 4.5.1),
dashCoreComponents (== 1.8.0),
dashTable (== 4.6.0),
R6,
fiery (> 1.0.0),
routr (> 0.2.0),
Expand All@@ -32,8 +32,8 @@ Collate:
'print.R'
'internal.R'
Remotes: plotly/dash-html-components@55c3884,
Comment thread
rpkyle marked this conversation as resolved.
plotly/dash-core-components@c107e0f,
plotly/dash-table@3058bd5
plotly/dash-core-components@fc153b4,
plotly/dash-table@79d46ca
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Expand Down
2 changes: 1 addition & 1 deletion NAMESPACE
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,4 +27,4 @@ importFrom(routr,RouteStack)
importFrom(routr,ressource_route)
importFrom(stats,setNames)
importFrom(tools,file_ext)
importFrom(utils,getFromNamespace)
importFrom(utils,getFromNamespace)
175 changes: 154 additions & 21 deletions R/dash.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,7 @@
#' @usage Dash
#'
#' @section Constructor: Dash$new(
#' name = "dash",
#' name = NULL,
#' server = fiery::Fire$new(),
#' assets_folder = 'assets',
#' assets_url_path = '/assets',
Expand All@@ -24,7 +24,7 @@
#' @section Arguments:
#' \tabular{lll}{
#' `name` \tab \tab Character. The name of the Dash application (placed in the `<title>`
#' of the HTML page).\cr
#' of the HTML page). DEPRECATED; please use `index_string()` or `interpolate_index()` instead.\cr
#' `server` \tab \tab The web server used to power the application.
#' Must be a [fiery::Fire] object.\cr
#' `assets_folder` \tab \tab Character. A path, relative to the current working directory,
Expand DownExpand Up@@ -100,6 +100,9 @@
#' from the Dash backend. The latter may offer improved performance relative
#' to callbacks written in R.
#' }
#' \item{`title("dash")`}{
#' The title of the app. If no title is supplied, Dash for R will use 'dash'.
#' }
#' \item{`callback_context()`}{
#' The `callback_context` method permits retrieving the inputs which triggered
#' the firing of a given callback, and allows introspection of the input/state
Expand All@@ -114,7 +117,63 @@
#' 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)`}{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

#' The `index_string` method allows the specification of a custom index by changing
Comment thread
rpkyle marked this conversation as 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 elements
#' and return an error if a valid index is not defined. The following interpolation keys are
#' currently supported:
#' \describe{
#' \item{`{%metas%}`}{Optional - The registered meta tags.}
#' \item{`{%favicon%}`}{Optional - A favicon link tag if found in assets.}
#' \item{`{%css%}`}{Optional - Link tags to css resources.}
#' \item{`{%config%}`}{Required - Config generated by dash for the renderer.}
#' \item{`{%app_entry%}`}{Required - The container where dash react components are rendered.}
#' \item{`{%scripts%}`}{Required - Collected dependencies scripts tags.}
#' }
#' \describe{
#' \item{Example of a basic HTML index string:}{
#' \preformatted{
#' "<!DOCTYPE html>
#' <html>
#' <head>
#' \{\%meta_tags\%\}
#' <title>\{\{%css\%\}\}</title>
#' \{\%favicon\%\}
#' \{\%css_tags\%\}
#' </head>
#' <body>
#' \{\%app_entry\%\}
#' <footer>
#' \{\%config\%\}
#' \{\%scripts\%\}
#' </footer>
#' </body>
#' </html>"
#' }
#' }
#' }
#' }
#' \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:
#' \preformatted{
#' 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{...}{Named List. The unnamed arguments 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{
Expand DownExpand Up@@ -174,7 +233,7 @@ Dash <- R6::R6Class(
config = list(),

# i.e., the Dash$new() method
initialize = function(name = "dash",
initialize = function(name = NULL,
server = fiery::Fire$new(),
assets_folder = 'assets',
assets_url_path = '/assets',
Expand All@@ -191,13 +250,18 @@ Dash <- R6::R6Class(
suppress_callback_exceptions = FALSE) {

# argument type checking
assertthat::assert_that(is.character(name))
assertthat::assert_that(inherits(server, "Fire"))
assertthat::assert_that(is.logical(serve_locally))
assertthat::assert_that(is.logical(suppress_callback_exceptions))

# save relevant args as private fields
private$name <- name
if (!is.null(name)) {
warning(sprintf(
"The supplied application title, '%s', should be set using the title() method, or passed via index_string() or interpolate_index(); it has been ignored, and 'dash' will be used instead.",
name),
call. = FALSE
)
}
private$serve_locally <- serve_locally
private$eager_loading <- eager_loading
# remove leading and trailing slash(es) if present
Expand DownExpand Up@@ -763,11 +827,44 @@ Dash <- R6::R6Class(
sep="/")))
},

# ------------------------------------------------------------------------
# specify a custom index string
# ------------------------------------------------------------------------
index_string = function(string) {
private$custom_index <- validate_keys(string)
},
Comment thread
rpkyle marked this conversation as 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)
}

invisible(validate_keys(names(kwargs)))

private$template_index <- template
},

# ------------------------------------------------------------------------
# specify a custom title
# ------------------------------------------------------------------------
title = function(string = "dash") {
assertthat::assert_that(is.character(string))
private$name <- string
},

# ------------------------------------------------------------------------
# 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,
Expand DownExpand Up@@ -1266,6 +1363,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>{%title%}</title>
{%favicon%}
{%css_tags%}
</head>
<body>
{%app_entry%}
<footer>
{%config%}
{%scripts%}
</footer>
</body>
</html>", NA),
.index = NULL,

generateReloadHash = function() {
Expand DownExpand Up@@ -1434,13 +1549,32 @@ 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$name))
private$name <- 'dash'

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
Expand All@@ -1450,23 +1584,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
)
}
}
)
)
Expand Down
30 changes: 30 additions & 0 deletions R/utils.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -1270,3 +1270,33 @@ tryCompress <- function(request, response) {
}
return(response$compress())
}

interpolate_str <- function(index_template, ...) {
# This function takes an index string, along with
# user specified keys for the html keys of the index
# and sets the default values of the keys to the
# ones specified by the keys themselves, returning
# the custom index template.
template = index_template
kwargs <- list(...)

for (name in names(kwargs)) {
key = paste0('\\{', name, '\\}')

template = sub(key, kwargs[[name]], template)
}
return(template)
}

validate_keys <- function(string) {
required_keys <- c("app_entry", "config", "scripts")

keys_present <- vapply(required_keys, function(x) grepl(x, string), logical(1))

if (!all(keys_present)) {
stop(sprintf("Did you forget to include %s in your index string?",
paste(names(keys_present[keys_present==FALSE]), collapse = ", ")))
} else {
return(string)
}
}
2 changes: 1 addition & 1 deletion README.md
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
[![CircleCI](https://circleci.com/gh/plotly/dashR/tree/dev.svg?style=svg)](https://circleci.com/gh/plotly/dashR/tree/dev)
[![CircleCI](https://circleci.com/gh/plotly/dashR/tree/master.svg?style=svg)](https://circleci.com/gh/plotly/dashR/tree/master)
[![GitHub](https://img.shields.io/github/license/plotly/dashR.svg?color=dark-green)](https://github.com/plotly/dashR/blob/master/LICENSE)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/y/plotly/dashR.svg?color=dark-green)](https://github.com/plotly/dashR/graphs/contributors)

Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Support for index page templating by HammadTheOne · Pull Request #168 · plotly/dashR · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f6c13a9
Dash for R v0.2.0 (#162)
rpkyle Jan 4, 2020
f81fcb5
Update README.md
rpkyle Jan 5, 2020
a58d4f2
Added initial implementation of index customization with strings
HammadTheOne Jan 9, 2020
4d72243
Fixed issue with `collect_assets` being undefined
HammadTheOne Jan 10, 2020
30251cf
Added description and details.
HammadTheOne Jan 10, 2020
3346a93
Added description
HammadTheOne Jan 14, 2020
2e58b37
Added error messages and warnings.
HammadTheOne Jan 14, 2020
0984660
Merge branch 'dev' into 42-index-page-templating
HammadTheOne Jan 14, 2020
3aa0f50
Updated version to 0.3.0
HammadTheOne Jan 16, 2020
a2410d5
Added CRLF
HammadTheOne Jan 16, 2020
a158a37
Updated environment variable names to `dev` versions.
HammadTheOne Jan 17, 2020
1138e4c
Improved error message function, made parity changes for index keys.
HammadTheOne Jan 17, 2020
fd67f8a
Added available keys to description.
HammadTheOne Jan 17, 2020
17a61d1
Parity changes to `app_entry` and `config` keys
HammadTheOne Jan 17, 2020
13ebec4
Cleaned up description.
HammadTheOne Jan 17, 2020
ab54aa0
Added `interpolate_str` helper function to `utils.R`
HammadTheOne Jan 17, 2020
ce4a8b6
Changes to default index, consolidating `_dash-config`
HammadTheOne Jan 17, 2020
036e4e5
Added template index and logic for choosing correct index.
HammadTheOne Jan 19, 2020
09b0851
Added description for `interpolate_index`.
HammadTheOne Jan 19, 2020
4023b67
Updated glue arguments in `index_string` method, added example index.
HammadTheOne Jan 27, 2020
8e98370
Update to `interpolate_index` to reflect changes to `index_string`.
HammadTheOne Jan 27, 2020
0ce3158
Bugfix, referenced correct private variable.
HammadTheOne Jan 27, 2020
7fd1ebe
Update R/dash.R
rpkyle Feb 6, 2020
a0c2f7e
:hocho: cat(template)
Feb 6, 2020
5ae7549
:camel: make concise
Feb 6, 2020
79b0faa
replace = with <-
Feb 6, 2020
39d52e0
:dromedary_camel: DRY up key validation logic
Feb 6, 2020
8b71875
:black_large_square: use invisible
Feb 6, 2020
f3dbfb9
use latest pkgs
Feb 11, 2020
e3a40c3
update package docs
Feb 11, 2020
df3d780
update docs; remove name, add title
Feb 11, 2020
84f8464
note title method
Feb 11, 2020
5bbba6e
:see_no_evil: need default app name
Feb 11, 2020
2aef1f3
:rotating_light: add integration tests
Feb 11, 2020
56904ba
fix ref for dcc
Feb 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions DESCRIPTION
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
Package: dash
Title: An Interface to the Dash Ecosystem for Authoring Reactive Web Applications
Version: 0.2.0
Version: 0.3.0
Authors@R: c(person("Chris", "Parmer", role = c("aut"), email = "chris@plot.ly"), person("Ryan Patrick", "Kyle", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-5829-9867"), email = "ryan@plot.ly"), person("Carson", "Sievert", role = c("aut"), comment = c(ORCID = "0000-0002-4958-2844")), person(family = "Plotly Technologies", role = "cph"))
Description: A framework for building analytical web applications, Dash offers a pleasant and productive development experience. No JavaScript required.
Depends:
R (>= 3.0.2)
Imports:
dashHtmlComponents (== 1.0.2),
Comment thread
rpkyle marked this conversation as resolved.
dashCoreComponents (== 1.6.0),
dashTable (== 4.5.1),
dashCoreComponents (== 1.8.0),
dashTable (== 4.6.0),
R6,
fiery (> 1.0.0),
routr (> 0.2.0),
Expand All@@ -32,8 +32,8 @@ Collate:
'print.R'
'internal.R'
Remotes: plotly/dash-html-components@55c3884,
Comment thread
rpkyle marked this conversation as resolved.
plotly/dash-core-components@c107e0f,
plotly/dash-table@3058bd5
plotly/dash-core-components@fc153b4,
plotly/dash-table@79d46ca
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Expand Down
2 changes: 1 addition & 1 deletion NAMESPACE
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,4 +27,4 @@ importFrom(routr,RouteStack)
importFrom(routr,ressource_route)
importFrom(stats,setNames)
importFrom(tools,file_ext)
importFrom(utils,getFromNamespace)
importFrom(utils,getFromNamespace)
175 changes: 154 additions & 21 deletions R/dash.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,7 @@
#' @usage Dash
#'
#' @section Constructor: Dash$new(
#' name = "dash",
#' name = NULL,
#' server = fiery::Fire$new(),
#' assets_folder = 'assets',
#' assets_url_path = '/assets',
Expand All@@ -24,7 +24,7 @@
#' @section Arguments:
#' \tabular{lll}{
#' `name` \tab \tab Character. The name of the Dash application (placed in the `<title>`
#' of the HTML page).\cr
#' of the HTML page). DEPRECATED; please use `index_string()` or `interpolate_index()` instead.\cr
#' `server` \tab \tab The web server used to power the application.
#' Must be a [fiery::Fire] object.\cr
#' `assets_folder` \tab \tab Character. A path, relative to the current working directory,
Expand DownExpand Up@@ -100,6 +100,9 @@
#' from the Dash backend. The latter may offer improved performance relative
#' to callbacks written in R.
#' }
#' \item{`title("dash")`}{
#' The title of the app. If no title is supplied, Dash for R will use 'dash'.
#' }
#' \item{`callback_context()`}{
#' The `callback_context` method permits retrieving the inputs which triggered
#' the firing of a given callback, and allows introspection of the input/state
Expand All@@ -114,7 +117,63 @@
#' 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)`}{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

#' The `index_string` method allows the specification of a custom index by changing
Comment thread
rpkyle marked this conversation as 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 elements
#' and return an error if a valid index is not defined. The following interpolation keys are
#' currently supported:
#' \describe{
#' \item{`{%metas%}`}{Optional - The registered meta tags.}
#' \item{`{%favicon%}`}{Optional - A favicon link tag if found in assets.}
#' \item{`{%css%}`}{Optional - Link tags to css resources.}
#' \item{`{%config%}`}{Required - Config generated by dash for the renderer.}
#' \item{`{%app_entry%}`}{Required - The container where dash react components are rendered.}
#' \item{`{%scripts%}`}{Required - Collected dependencies scripts tags.}
#' }
#' \describe{
#' \item{Example of a basic HTML index string:}{
#' \preformatted{
#' "<!DOCTYPE html>
#' <html>
#' <head>
#' \{\%meta_tags\%\}
#' <title>\{\{%css\%\}\}</title>
#' \{\%favicon\%\}
#' \{\%css_tags\%\}
#' </head>
#' <body>
#' \{\%app_entry\%\}
#' <footer>
#' \{\%config\%\}
#' \{\%scripts\%\}
#' </footer>
#' </body>
#' </html>"
#' }
#' }
#' }
#' }
#' \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:
#' \preformatted{
#' 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{...}{Named List. The unnamed arguments 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{
Expand DownExpand Up@@ -174,7 +233,7 @@ Dash <- R6::R6Class(
config = list(),

# i.e., the Dash$new() method
initialize = function(name = "dash",
initialize = function(name = NULL,
server = fiery::Fire$new(),
assets_folder = 'assets',
assets_url_path = '/assets',
Expand All@@ -191,13 +250,18 @@ Dash <- R6::R6Class(
suppress_callback_exceptions = FALSE) {

# argument type checking
assertthat::assert_that(is.character(name))
assertthat::assert_that(inherits(server, "Fire"))
assertthat::assert_that(is.logical(serve_locally))
assertthat::assert_that(is.logical(suppress_callback_exceptions))

# save relevant args as private fields
private$name <- name
if (!is.null(name)) {
warning(sprintf(
"The supplied application title, '%s', should be set using the title() method, or passed via index_string() or interpolate_index(); it has been ignored, and 'dash' will be used instead.",
name),
call. = FALSE
)
}
private$serve_locally <- serve_locally
private$eager_loading <- eager_loading
# remove leading and trailing slash(es) if present
Expand DownExpand Up@@ -763,11 +827,44 @@ Dash <- R6::R6Class(
sep="/")))
},

# ------------------------------------------------------------------------
# specify a custom index string
# ------------------------------------------------------------------------
index_string = function(string) {
private$custom_index <- validate_keys(string)
},
Comment thread
rpkyle marked this conversation as 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)
}

invisible(validate_keys(names(kwargs)))

private$template_index <- template
},

# ------------------------------------------------------------------------
# specify a custom title
# ------------------------------------------------------------------------
title = function(string = "dash") {
assertthat::assert_that(is.character(string))
private$name <- string
},

# ------------------------------------------------------------------------
# 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,
Expand DownExpand Up@@ -1266,6 +1363,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>{%title%}</title>
{%favicon%}
{%css_tags%}
</head>
<body>
{%app_entry%}
<footer>
{%config%}
{%scripts%}
</footer>
</body>
</html>", NA),
.index = NULL,

generateReloadHash = function() {
Expand DownExpand Up@@ -1434,13 +1549,32 @@ 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$name))
private$name <- 'dash'

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
Expand All@@ -1450,23 +1584,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
)
}
}
)
)
Expand Down
30 changes: 30 additions & 0 deletions R/utils.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -1270,3 +1270,33 @@ tryCompress <- function(request, response) {
}
return(response$compress())
}

interpolate_str <- function(index_template, ...) {
# This function takes an index string, along with
# user specified keys for the html keys of the index
# and sets the default values of the keys to the
# ones specified by the keys themselves, returning
# the custom index template.
template = index_template
kwargs <- list(...)

for (name in names(kwargs)) {
key = paste0('\\{', name, '\\}')

template = sub(key, kwargs[[name]], template)
}
return(template)
}

validate_keys <- function(string) {
required_keys <- c("app_entry", "config", "scripts")

keys_present <- vapply(required_keys, function(x) grepl(x, string), logical(1))

if (!all(keys_present)) {
stop(sprintf("Did you forget to include %s in your index string?",
paste(names(keys_present[keys_present==FALSE]), collapse = ", ")))
} else {
return(string)
}
}
2 changes: 1 addition & 1 deletion README.md
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
[![CircleCI](https://circleci.com/gh/plotly/dashR/tree/dev.svg?style=svg)](https://circleci.com/gh/plotly/dashR/tree/dev)
[![CircleCI](https://circleci.com/gh/plotly/dashR/tree/master.svg?style=svg)](https://circleci.com/gh/plotly/dashR/tree/master)
[![GitHub](https://img.shields.io/github/license/plotly/dashR.svg?color=dark-green)](https://github.com/plotly/dashR/blob/master/LICENSE)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/y/plotly/dashR.svg?color=dark-green)](https://github.com/plotly/dashR/graphs/contributors)

Expand Down
Loading