Skip to content
Merged
Changes from all commits
Commits
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
116 changes: 58 additions & 58 deletions R/dash.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,7 +50,7 @@ Dash <- R6::R6Class(
#' as `integrity` and `crossorigin`.
#' @param external_stylesheets List. An optional list of valid URLs from which
#' to serve CSS for rendered pages. Each entry can be a string (the URL) or a list
#' with `href` (the URL) and optionally other `<link>` tag attributes such as
#' with `href` (the URL) and optionally other `<link>` tag attributes such as
#' `rel`, `integrity` and `crossorigin`.
#' @param compress Logical. Whether to try to compress files and data served by Fiery.
#' By default, `brotli` is attempted first, then `gzip`, then the `deflate` algorithm,
Expand DownExpand Up@@ -116,9 +116,9 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------
router <- routr::RouteStack$new()
server$set_data("user-routes", list()) # placeholder for custom routes

# ensure that assets_folder is neither NULL nor character(0)
if (!(is.null(private$assets_folder)) && length(private$assets_folder) != 0) {
if (!(is.null(private$assets_folder)) & length(private$assets_folder) != 0) {
if (!(dir.exists(private$assets_folder)) && gsub("/+", "", assets_folder) != "assets") {
warning(sprintf(
"The supplied assets folder, '%s', could not be found in the project directory.",
Expand DownExpand Up@@ -618,9 +618,9 @@ Dash <- R6::R6Class(
#' library(dash)
#' app <- Dash$new()
#'
#' # A handler to redirect requests with `307` status code (temporary redirects);
#' # A handler to redirect requests with `307` status code (temporary redirects);
#' # for permanent redirects (`301`), see the `redirect` method described below
#' #
#' #
#' # A simple single path-to-path redirect
#' app$server_route('/getting-started', function(request, response, keys, ...) {
#' response$status <- 307L
Expand DownExpand Up@@ -653,11 +653,11 @@ Dash <- R6::R6Class(
"methods" = methods)

self$server$set_data("user-routes", user_routes)
},
},

#' @description
#' Redirect a Dash application URL path
#' @details
#' @details
#' This is a convenience method to simplify adding redirects
#' for your Dash application which automatically return a `301`
#' HTTP status code and direct the client to load an alternate URL.
Expand DownExpand Up@@ -705,7 +705,7 @@ Dash <- R6::R6Class(
TRUE
}
}

self$server_route(old_path, handler)
},

Expand All@@ -714,13 +714,13 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------------------
#' @description
#' Retrieves the Dash application layout.
#' @details
#' @details
#' If render is `TRUE`, and the layout is a function,
#' the result of the function (rather than the function itself) is returned.
#' @param render Logical. If the layout is a function, should the function be
#' executed to return the layout? If `FALSE`, the function is returned as-is.
#' @return List or function, depending on the value of `render` (see above).
#' When returning an object of class `dash_component`, the default `print`
#' @return List or function, depending on the value of `render` (see above).
#' When returning an object of class `dash_component`, the default `print`
#' method for this class will display the corresponding pretty-printed JSON
#' representation of the object to the console.
layout_get = function(render = TRUE) {
Expand All@@ -739,7 +739,7 @@ Dash <- R6::R6Class(
#' class.
#' @param value An object of the `dash_component` class, which provides
#' a component or collection of components, specified either as a Dash
#' component or a function that returns a Dash component.
#' component or a function that returns a Dash component.
layout = function(value) {
# private$layout_ <- if (is.function(..1)) ..1 else list(...)
private$layout_ <- value
Expand DownExpand Up@@ -769,9 +769,9 @@ Dash <- R6::R6Class(
#' @description
#' Define a Dash callback.
#' @details
#' Describes a server or clientside callback relating the values of one or more
#' Describes a server or clientside callback relating the values of one or more
#' `output` items to one or more `input` items which will trigger the callback
#' when they change, and optionally `state` items which provide additional
#' when they change, and optionally `state` items which provide additional
#' information but do not trigger the callback directly.
#'
#' For detailed examples of how to use pattern-matching callbacks, see the
Expand All@@ -784,13 +784,13 @@ Dash <- R6::R6Class(
#' object(s) (which should reference layout components), which become
#' argument values for R callback handlers defined in `func`.
#'
#' Here `func` may either be an anonymous R function, a JavaScript function
#' Here `func` may either be an anonymous R function, a JavaScript function
#' provided as a character string, or a call to `clientsideFunction()`, which
#' describes a locally served JavaScript function instead. The latter
#' two methods define a "clientside callback", which updates components
#' without passing data to and from the Dash backend. The latter may offer
#' improved performance relative to callbacks written purely in R.
#' @param output Named list. The `output` argument provides the component `id`
#' @param output Named list. The `output` argument provides the component `id`
#' and `property` which will be updated by the callback; a callback can
#' target one or more outputs (i.e. multiple outputs).
#' @param params Unnamed list; provides [input] and [state] statements, each
Expand DownExpand Up@@ -852,12 +852,12 @@ Dash <- R6::R6Class(
#' the firing of a given callback, and allows introspection of the input/state
#' values given their names. It is only available from within a callback;
#' attempting to use this method outside of a callback will result in a warning.
#'
#'
#' The `callback_context` method returns a list containing three elements:
#' `states`, `triggered`, `inputs`. The first and last of these correspond to
#' the values of `states` and `inputs` for the current invocation of the
#' callback, and `triggered` provides a list of changed properties.
#'
#'
#' @return List comprising elements `states`, `triggered`, `inputs`.
callback_context = function() {
if (is.null(private$callback_context_)) {
Expand All@@ -877,14 +877,14 @@ Dash <- R6::R6Class(
#' duration required to execute a given callback. It may only be called
#' from within a callback; a warning will be thrown and the method will
#' otherwise return `NULL` if invoked outside of a callback.
#'
#'
#' @param name Character. The name of the resource.
#' @param duration Numeric. The time in seconds to report. Internally, this is
#' rounded to the nearest millisecond.
#' @param description Character. A description of the resource.
#'
callback_context.record_timing = function(name,
duration=NULL,
duration=NULL,
description=NULL) {
if (is.null(private$callback_context_)) {
warning("callback_context is undefined; callback_context.record_timing may only be accessed within a callback.")
Expand All@@ -897,7 +897,7 @@ Dash <- R6::R6Class(
stop(paste0("Duplicate resource name ", name, " found."), call.=FALSE)
}

timing_information[[name]] <- list("dur" = round(duration * 1000),
timing_information[[name]] <- list("dur" = round(duration * 1000),
"desc" = description)

self$server$set_data("timing-information", timing_information)
Expand All@@ -906,9 +906,9 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------------------
# return asset URLs
# ------------------------------------------------------------------------
#' @description
#' @description
#' Return a URL for a Dash asset.
#' @details
#' @details
#' The `get_asset_url` method permits retrieval of an asset's URL given its filename.
#' For example, `app$get_asset_url('style.css')` should return `/assets/style.css` when
#' `assets_folder = 'assets'`. By default, the prefix is the value of `requests_pathname_prefix`,
Expand DownExpand Up@@ -973,7 +973,7 @@ Dash <- R6::R6Class(
#' in components such as `dccLink` or `dccLocation`. For example, `app$get_relative_url("/page/")`
#' would return `/app/page/` for an app running on a deployment server. The path must be prefixed with
#' a `/`.
#' @param path Character. A path string prefixed with a leading `/` which directs
#' @param path Character. A path string prefixed with a leading `/` which directs
#' at a path or asset directory.
#' @param requests_pathname_prefix Character. The pathname prefix for the application when
#' deployed. Defaults to the environment variable set by the server,
Expand All@@ -984,12 +984,12 @@ Dash <- R6::R6Class(
asset = get_relative_path(requests_pathname = requests_pathname_prefix, path = path)
return(asset)
},


# ------------------------------------------------------------------------
# return relative asset URLs
# ------------------------------------------------------------------------

#' @description
#' Return a Dash asset path without its prefix.
#' @details
Expand All@@ -998,7 +998,7 @@ Dash <- R6::R6Class(
#' method, by taking a `relative path` as an input, and returning the `path` stripped of the `requests_pathname_prefix`,
#' and any leading or trailing `/`. For example, a path string `/app/homepage/`, would be returned as
#' `homepage`. This is particularly useful for `dccLocation` URL routing.
#' @param path Character. A path string prefixed with a leading `/` which directs
#' @param path Character. A path string prefixed with a leading `/` which directs
#' at a path or asset directory.
#' @param requests_pathname_prefix Character. The pathname prefix for the app on
#' a deployed application. Defaults to the environment variable set by the server,
Expand All@@ -1014,7 +1014,7 @@ Dash <- R6::R6Class(
#' Specify a custom index string for a Dash application.
#' @details
#' The `index_string` method allows the specification of a custom index by changing
#' the default `HTML` template that is generated by the Dash UI. #' Meta tags, CSS, and JavaScript are some examples of features
#' the default `HTML` template that is generated by the Dash UI. #' Meta tags, CSS, and 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
Expand DownExpand Up@@ -1054,11 +1054,11 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(string))
private$custom_index <- validate_keys(string, is_template=TRUE)
},

# ------------------------------------------------------------------------
# modify the templated variables by using the `interpolate_index` method.
# modify the templated variables by using the `interpolate_index` method.
# ------------------------------------------------------------------------
#' @description
#' @description
#' Modify index template variables for a Dash application.
#' @details
#' With the `interpolate_index` method, one can pass a custom index with template string
Expand DownExpand Up@@ -1087,14 +1087,14 @@ Dash <- R6::R6Class(
#' </footer>
#' </body>
#' </html>"
#'
#'

#' # this is the default configuration, but custom configurations
#' # are possible -- the structure of the "config" argument is
#' # a list, in which each element is a JSON key/value pair, when
#' # reformatted as JSON from the list:
#' # e.g. {"routes_pathname_prefix":"/", "ui":false}
#' config <- sprintf("<script id='_dash-config' type='application/json'> %s </script>",
#' config <- sprintf("<script id='_dash-config' type='application/json'> %s </script>",
#' jsonlite::toJSON(app$config, auto_unbox=TRUE))
#'
#' app$interpolate_index(
Expand All@@ -1107,17 +1107,17 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(template_index))
template <- template_index
kwargs <- list(...)

for (name in names(kwargs)) {
key = paste0('\\{\\%', name, '\\%\\}')
template = sub(key, kwargs[[name]], template)
}

}
invisible(validate_keys(names(kwargs), is_template=FALSE))

private$template_index <- template
},

# ------------------------------------------------------------------------
# specify a custom title
# ------------------------------------------------------------------------
Expand All@@ -1130,7 +1130,7 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(string))
private$name <- string
},

# ------------------------------------------------------------------------
# convenient fiery wrappers
# ------------------------------------------------------------------------
Expand All@@ -1155,7 +1155,7 @@ Dash <- R6::R6Class(
#' @param dev_tools_prune_errors Logical. Reduce tracebacks such that only lines relevant to user code remain, stripping out Fiery and Dash references? Only available with debugging. `TRUE` by default, set to `FALSE` to see the complete traceback. Environment variable: `DASH_PRUNE_ERRORS`.
#' @param dev_tools_silence_routes_logging Logical. Replace Fiery's default logger with `dashLogger` instead (will remove all routes logging)? Enabled with debugging by default because hot reload hash checks generate a lot of requests.
#' @param ... Additional arguments to pass to the `start` handler; see the [fiery] documentation for relevant examples.
#' @examples
#' @examples
#' if (interactive() && require(dash)) {
#' library(dashCoreComponents)
#' library(dashHtmlComponents)
Expand DownExpand Up@@ -1232,7 +1232,7 @@ Dash <- R6::R6Class(

# attach user-defined routes, if they exist
if (length(self$server$get_data("user-routes")) > 0) {

plugin <- list(
on_attach = function(server) {
user_routes <- server$get_data("user-routes")
Expand All@@ -1243,26 +1243,26 @@ Dash <- R6::R6Class(
# have all the relevant routes in place anyhow
if (server$plugins$request_routr$has_route("user-routes"))
server$plugins$request_routr$remove_route("user-routes")

router <- server$plugins$request_routr

route <- routr::Route$new()

for (routing in user_routes) {
route$add_handler(method=routing$methods,
path=routing$path,
handler=routing$handler)
}

router$add_route(route, "user-routes")
},
name = "user_routes",
require = "request_routr"
)

self$server$attach(plugin, force = TRUE)
}

if(getAppPath() != FALSE) {
source_dir <- dirname(getAppPath())
private$app_root_modtime <- modtimeFromPath(source_dir, recursive = TRUE, asset_path = private$assets_folder)
Expand DownExpand Up@@ -1304,7 +1304,7 @@ Dash <- R6::R6Class(
timing_information <- self$server$get_data('timing-information')
dash_total <- timing_information[['__dash_server']]
timing_information[['__dash_server']][['dur']] <- round((as.numeric(Sys.time()) - dash_total[['dur']]) * 1000)

header_as_string <- list()

for (item in seq_along(timing_information)) {
Expand All@@ -1317,11 +1317,11 @@ Dash <- R6::R6Class(
if (!is.null(timing_information[[item]]$dur)) {
header_content <- paste0(header_content, ';dur=', timing_information[[item]]$dur)
}

header_as_string[[item]] <- header_content
}

request$response$append_header('Server-Timing',
request$response$append_header('Server-Timing',
paste0(unlist(header_as_string), collapse=", "))
})
}
Expand DownExpand Up@@ -1443,7 +1443,7 @@ Dash <- R6::R6Class(
# flush the context to prepare for the next request cycle
self$server$set_data("timing-information", list())
})
}
}

self$server$ignite(block = block, showcase = showcase, ...)
}
Expand DownExpand Up@@ -1501,10 +1501,10 @@ Dash <- R6::R6Class(
layout_ids = NULL,
layout_render = function() {
layout_ <- if (is.function(private$layout_)) private$layout_() else private$layout_

# ensure that the layout is a component, or a collection of components
layout_ <- private$componentify(layout_)

# store the layout as a (flattened) vector form since we query the
# vector names several times to verify ID naming (among other things)
layout_flat <- rapply(layout_, I)
Expand All@@ -1518,7 +1518,7 @@ Dash <- R6::R6Class(

if (duped) {
duped_ids <- paste(layout_ids[duplicated(layout_ids)], collapse = ", ")

stop(
sprintf("layout ids must be unique -- please check the following list of duplicated ids: '%s'", duped_ids),
call. = FALSE
Expand DownExpand Up@@ -1942,21 +1942,21 @@ Dash <- R6::R6Class(

# 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
}
Expand Down
, '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" + '
Revert "use correct non-vectorized version of logical and" by alexcjohnson · Pull Request #255 · plotly/dashR · GitHub
Skip to content
Merged
Changes from all commits
Commits
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
116 changes: 58 additions & 58 deletions R/dash.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,7 +50,7 @@ Dash <- R6::R6Class(
#' as `integrity` and `crossorigin`.
#' @param external_stylesheets List. An optional list of valid URLs from which
#' to serve CSS for rendered pages. Each entry can be a string (the URL) or a list
#' with `href` (the URL) and optionally other `<link>` tag attributes such as
#' with `href` (the URL) and optionally other `<link>` tag attributes such as
#' `rel`, `integrity` and `crossorigin`.
#' @param compress Logical. Whether to try to compress files and data served by Fiery.
#' By default, `brotli` is attempted first, then `gzip`, then the `deflate` algorithm,
Expand DownExpand Up@@ -116,9 +116,9 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------
router <- routr::RouteStack$new()
server$set_data("user-routes", list()) # placeholder for custom routes

# ensure that assets_folder is neither NULL nor character(0)
if (!(is.null(private$assets_folder)) && length(private$assets_folder) != 0) {
if (!(is.null(private$assets_folder)) & length(private$assets_folder) != 0) {
if (!(dir.exists(private$assets_folder)) && gsub("/+", "", assets_folder) != "assets") {
warning(sprintf(
"The supplied assets folder, '%s', could not be found in the project directory.",
Expand DownExpand Up@@ -618,9 +618,9 @@ Dash <- R6::R6Class(
#' library(dash)
#' app <- Dash$new()
#'
#' # A handler to redirect requests with `307` status code (temporary redirects);
#' # A handler to redirect requests with `307` status code (temporary redirects);
#' # for permanent redirects (`301`), see the `redirect` method described below
#' #
#' #
#' # A simple single path-to-path redirect
#' app$server_route('/getting-started', function(request, response, keys, ...) {
#' response$status <- 307L
Expand DownExpand Up@@ -653,11 +653,11 @@ Dash <- R6::R6Class(
"methods" = methods)

self$server$set_data("user-routes", user_routes)
},
},

#' @description
#' Redirect a Dash application URL path
#' @details
#' @details
#' This is a convenience method to simplify adding redirects
#' for your Dash application which automatically return a `301`
#' HTTP status code and direct the client to load an alternate URL.
Expand DownExpand Up@@ -705,7 +705,7 @@ Dash <- R6::R6Class(
TRUE
}
}

self$server_route(old_path, handler)
},

Expand All@@ -714,13 +714,13 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------------------
#' @description
#' Retrieves the Dash application layout.
#' @details
#' @details
#' If render is `TRUE`, and the layout is a function,
#' the result of the function (rather than the function itself) is returned.
#' @param render Logical. If the layout is a function, should the function be
#' executed to return the layout? If `FALSE`, the function is returned as-is.
#' @return List or function, depending on the value of `render` (see above).
#' When returning an object of class `dash_component`, the default `print`
#' @return List or function, depending on the value of `render` (see above).
#' When returning an object of class `dash_component`, the default `print`
#' method for this class will display the corresponding pretty-printed JSON
#' representation of the object to the console.
layout_get = function(render = TRUE) {
Expand All@@ -739,7 +739,7 @@ Dash <- R6::R6Class(
#' class.
#' @param value An object of the `dash_component` class, which provides
#' a component or collection of components, specified either as a Dash
#' component or a function that returns a Dash component.
#' component or a function that returns a Dash component.
layout = function(value) {
# private$layout_ <- if (is.function(..1)) ..1 else list(...)
private$layout_ <- value
Expand DownExpand Up@@ -769,9 +769,9 @@ Dash <- R6::R6Class(
#' @description
#' Define a Dash callback.
#' @details
#' Describes a server or clientside callback relating the values of one or more
#' Describes a server or clientside callback relating the values of one or more
#' `output` items to one or more `input` items which will trigger the callback
#' when they change, and optionally `state` items which provide additional
#' when they change, and optionally `state` items which provide additional
#' information but do not trigger the callback directly.
#'
#' For detailed examples of how to use pattern-matching callbacks, see the
Expand All@@ -784,13 +784,13 @@ Dash <- R6::R6Class(
#' object(s) (which should reference layout components), which become
#' argument values for R callback handlers defined in `func`.
#'
#' Here `func` may either be an anonymous R function, a JavaScript function
#' Here `func` may either be an anonymous R function, a JavaScript function
#' provided as a character string, or a call to `clientsideFunction()`, which
#' describes a locally served JavaScript function instead. The latter
#' two methods define a "clientside callback", which updates components
#' without passing data to and from the Dash backend. The latter may offer
#' improved performance relative to callbacks written purely in R.
#' @param output Named list. The `output` argument provides the component `id`
#' @param output Named list. The `output` argument provides the component `id`
#' and `property` which will be updated by the callback; a callback can
#' target one or more outputs (i.e. multiple outputs).
#' @param params Unnamed list; provides [input] and [state] statements, each
Expand DownExpand Up@@ -852,12 +852,12 @@ Dash <- R6::R6Class(
#' the firing of a given callback, and allows introspection of the input/state
#' values given their names. It is only available from within a callback;
#' attempting to use this method outside of a callback will result in a warning.
#'
#'
#' The `callback_context` method returns a list containing three elements:
#' `states`, `triggered`, `inputs`. The first and last of these correspond to
#' the values of `states` and `inputs` for the current invocation of the
#' callback, and `triggered` provides a list of changed properties.
#'
#'
#' @return List comprising elements `states`, `triggered`, `inputs`.
callback_context = function() {
if (is.null(private$callback_context_)) {
Expand All@@ -877,14 +877,14 @@ Dash <- R6::R6Class(
#' duration required to execute a given callback. It may only be called
#' from within a callback; a warning will be thrown and the method will
#' otherwise return `NULL` if invoked outside of a callback.
#'
#'
#' @param name Character. The name of the resource.
#' @param duration Numeric. The time in seconds to report. Internally, this is
#' rounded to the nearest millisecond.
#' @param description Character. A description of the resource.
#'
callback_context.record_timing = function(name,
duration=NULL,
duration=NULL,
description=NULL) {
if (is.null(private$callback_context_)) {
warning("callback_context is undefined; callback_context.record_timing may only be accessed within a callback.")
Expand All@@ -897,7 +897,7 @@ Dash <- R6::R6Class(
stop(paste0("Duplicate resource name ", name, " found."), call.=FALSE)
}

timing_information[[name]] <- list("dur" = round(duration * 1000),
timing_information[[name]] <- list("dur" = round(duration * 1000),
"desc" = description)

self$server$set_data("timing-information", timing_information)
Expand All@@ -906,9 +906,9 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------------------
# return asset URLs
# ------------------------------------------------------------------------
#' @description
#' @description
#' Return a URL for a Dash asset.
#' @details
#' @details
#' The `get_asset_url` method permits retrieval of an asset's URL given its filename.
#' For example, `app$get_asset_url('style.css')` should return `/assets/style.css` when
#' `assets_folder = 'assets'`. By default, the prefix is the value of `requests_pathname_prefix`,
Expand DownExpand Up@@ -973,7 +973,7 @@ Dash <- R6::R6Class(
#' in components such as `dccLink` or `dccLocation`. For example, `app$get_relative_url("/page/")`
#' would return `/app/page/` for an app running on a deployment server. The path must be prefixed with
#' a `/`.
#' @param path Character. A path string prefixed with a leading `/` which directs
#' @param path Character. A path string prefixed with a leading `/` which directs
#' at a path or asset directory.
#' @param requests_pathname_prefix Character. The pathname prefix for the application when
#' deployed. Defaults to the environment variable set by the server,
Expand All@@ -984,12 +984,12 @@ Dash <- R6::R6Class(
asset = get_relative_path(requests_pathname = requests_pathname_prefix, path = path)
return(asset)
},


# ------------------------------------------------------------------------
# return relative asset URLs
# ------------------------------------------------------------------------

#' @description
#' Return a Dash asset path without its prefix.
#' @details
Expand All@@ -998,7 +998,7 @@ Dash <- R6::R6Class(
#' method, by taking a `relative path` as an input, and returning the `path` stripped of the `requests_pathname_prefix`,
#' and any leading or trailing `/`. For example, a path string `/app/homepage/`, would be returned as
#' `homepage`. This is particularly useful for `dccLocation` URL routing.
#' @param path Character. A path string prefixed with a leading `/` which directs
#' @param path Character. A path string prefixed with a leading `/` which directs
#' at a path or asset directory.
#' @param requests_pathname_prefix Character. The pathname prefix for the app on
#' a deployed application. Defaults to the environment variable set by the server,
Expand All@@ -1014,7 +1014,7 @@ Dash <- R6::R6Class(
#' Specify a custom index string for a Dash application.
#' @details
#' The `index_string` method allows the specification of a custom index by changing
#' the default `HTML` template that is generated by the Dash UI. #' Meta tags, CSS, and JavaScript are some examples of features
#' the default `HTML` template that is generated by the Dash UI. #' Meta tags, CSS, and 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
Expand DownExpand Up@@ -1054,11 +1054,11 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(string))
private$custom_index <- validate_keys(string, is_template=TRUE)
},

# ------------------------------------------------------------------------
# modify the templated variables by using the `interpolate_index` method.
# modify the templated variables by using the `interpolate_index` method.
# ------------------------------------------------------------------------
#' @description
#' @description
#' Modify index template variables for a Dash application.
#' @details
#' With the `interpolate_index` method, one can pass a custom index with template string
Expand DownExpand Up@@ -1087,14 +1087,14 @@ Dash <- R6::R6Class(
#' </footer>
#' </body>
#' </html>"
#'
#'

#' # this is the default configuration, but custom configurations
#' # are possible -- the structure of the "config" argument is
#' # a list, in which each element is a JSON key/value pair, when
#' # reformatted as JSON from the list:
#' # e.g. {"routes_pathname_prefix":"/", "ui":false}
#' config <- sprintf("<script id='_dash-config' type='application/json'> %s </script>",
#' config <- sprintf("<script id='_dash-config' type='application/json'> %s </script>",
#' jsonlite::toJSON(app$config, auto_unbox=TRUE))
#'
#' app$interpolate_index(
Expand All@@ -1107,17 +1107,17 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(template_index))
template <- template_index
kwargs <- list(...)

for (name in names(kwargs)) {
key = paste0('\\{\\%', name, '\\%\\}')
template = sub(key, kwargs[[name]], template)
}

}
invisible(validate_keys(names(kwargs), is_template=FALSE))

private$template_index <- template
},

# ------------------------------------------------------------------------
# specify a custom title
# ------------------------------------------------------------------------
Expand All@@ -1130,7 +1130,7 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(string))
private$name <- string
},

# ------------------------------------------------------------------------
# convenient fiery wrappers
# ------------------------------------------------------------------------
Expand All@@ -1155,7 +1155,7 @@ Dash <- R6::R6Class(
#' @param dev_tools_prune_errors Logical. Reduce tracebacks such that only lines relevant to user code remain, stripping out Fiery and Dash references? Only available with debugging. `TRUE` by default, set to `FALSE` to see the complete traceback. Environment variable: `DASH_PRUNE_ERRORS`.
#' @param dev_tools_silence_routes_logging Logical. Replace Fiery's default logger with `dashLogger` instead (will remove all routes logging)? Enabled with debugging by default because hot reload hash checks generate a lot of requests.
#' @param ... Additional arguments to pass to the `start` handler; see the [fiery] documentation for relevant examples.
#' @examples
#' @examples
#' if (interactive() && require(dash)) {
#' library(dashCoreComponents)
#' library(dashHtmlComponents)
Expand DownExpand Up@@ -1232,7 +1232,7 @@ Dash <- R6::R6Class(

# attach user-defined routes, if they exist
if (length(self$server$get_data("user-routes")) > 0) {

plugin <- list(
on_attach = function(server) {
user_routes <- server$get_data("user-routes")
Expand All@@ -1243,26 +1243,26 @@ Dash <- R6::R6Class(
# have all the relevant routes in place anyhow
if (server$plugins$request_routr$has_route("user-routes"))
server$plugins$request_routr$remove_route("user-routes")

router <- server$plugins$request_routr

route <- routr::Route$new()

for (routing in user_routes) {
route$add_handler(method=routing$methods,
path=routing$path,
handler=routing$handler)
}

router$add_route(route, "user-routes")
},
name = "user_routes",
require = "request_routr"
)

self$server$attach(plugin, force = TRUE)
}

if(getAppPath() != FALSE) {
source_dir <- dirname(getAppPath())
private$app_root_modtime <- modtimeFromPath(source_dir, recursive = TRUE, asset_path = private$assets_folder)
Expand DownExpand Up@@ -1304,7 +1304,7 @@ Dash <- R6::R6Class(
timing_information <- self$server$get_data('timing-information')
dash_total <- timing_information[['__dash_server']]
timing_information[['__dash_server']][['dur']] <- round((as.numeric(Sys.time()) - dash_total[['dur']]) * 1000)

header_as_string <- list()

for (item in seq_along(timing_information)) {
Expand All@@ -1317,11 +1317,11 @@ Dash <- R6::R6Class(
if (!is.null(timing_information[[item]]$dur)) {
header_content <- paste0(header_content, ';dur=', timing_information[[item]]$dur)
}

header_as_string[[item]] <- header_content
}

request$response$append_header('Server-Timing',
request$response$append_header('Server-Timing',
paste0(unlist(header_as_string), collapse=", "))
})
}
Expand DownExpand Up@@ -1443,7 +1443,7 @@ Dash <- R6::R6Class(
# flush the context to prepare for the next request cycle
self$server$set_data("timing-information", list())
})
}
}

self$server$ignite(block = block, showcase = showcase, ...)
}
Expand DownExpand Up@@ -1501,10 +1501,10 @@ Dash <- R6::R6Class(
layout_ids = NULL,
layout_render = function() {
layout_ <- if (is.function(private$layout_)) private$layout_() else private$layout_

# ensure that the layout is a component, or a collection of components
layout_ <- private$componentify(layout_)

# store the layout as a (flattened) vector form since we query the
# vector names several times to verify ID naming (among other things)
layout_flat <- rapply(layout_, I)
Expand All@@ -1518,7 +1518,7 @@ Dash <- R6::R6Class(

if (duped) {
duped_ids <- paste(layout_ids[duplicated(layout_ids)], collapse = ", ")

stop(
sprintf("layout ids must be unique -- please check the following list of duplicated ids: '%s'", duped_ids),
call. = FALSE
Expand DownExpand Up@@ -1942,21 +1942,21 @@ Dash <- R6::R6Class(

# 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
}
Expand Down
, '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('^' + ".*" + ' Revert "use correct non-vectorized version of logical and" by alexcjohnson · Pull Request #255 · plotly/dashR · GitHub
Skip to content
Merged
Changes from all commits
Commits
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
116 changes: 58 additions & 58 deletions R/dash.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,7 +50,7 @@ Dash <- R6::R6Class(
#' as `integrity` and `crossorigin`.
#' @param external_stylesheets List. An optional list of valid URLs from which
#' to serve CSS for rendered pages. Each entry can be a string (the URL) or a list
#' with `href` (the URL) and optionally other `<link>` tag attributes such as
#' with `href` (the URL) and optionally other `<link>` tag attributes such as
#' `rel`, `integrity` and `crossorigin`.
#' @param compress Logical. Whether to try to compress files and data served by Fiery.
#' By default, `brotli` is attempted first, then `gzip`, then the `deflate` algorithm,
Expand DownExpand Up@@ -116,9 +116,9 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------
router <- routr::RouteStack$new()
server$set_data("user-routes", list()) # placeholder for custom routes

# ensure that assets_folder is neither NULL nor character(0)
if (!(is.null(private$assets_folder)) && length(private$assets_folder) != 0) {
if (!(is.null(private$assets_folder)) & length(private$assets_folder) != 0) {
if (!(dir.exists(private$assets_folder)) && gsub("/+", "", assets_folder) != "assets") {
warning(sprintf(
"The supplied assets folder, '%s', could not be found in the project directory.",
Expand DownExpand Up@@ -618,9 +618,9 @@ Dash <- R6::R6Class(
#' library(dash)
#' app <- Dash$new()
#'
#' # A handler to redirect requests with `307` status code (temporary redirects);
#' # A handler to redirect requests with `307` status code (temporary redirects);
#' # for permanent redirects (`301`), see the `redirect` method described below
#' #
#' #
#' # A simple single path-to-path redirect
#' app$server_route('/getting-started', function(request, response, keys, ...) {
#' response$status <- 307L
Expand DownExpand Up@@ -653,11 +653,11 @@ Dash <- R6::R6Class(
"methods" = methods)

self$server$set_data("user-routes", user_routes)
},
},

#' @description
#' Redirect a Dash application URL path
#' @details
#' @details
#' This is a convenience method to simplify adding redirects
#' for your Dash application which automatically return a `301`
#' HTTP status code and direct the client to load an alternate URL.
Expand DownExpand Up@@ -705,7 +705,7 @@ Dash <- R6::R6Class(
TRUE
}
}

self$server_route(old_path, handler)
},

Expand All@@ -714,13 +714,13 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------------------
#' @description
#' Retrieves the Dash application layout.
#' @details
#' @details
#' If render is `TRUE`, and the layout is a function,
#' the result of the function (rather than the function itself) is returned.
#' @param render Logical. If the layout is a function, should the function be
#' executed to return the layout? If `FALSE`, the function is returned as-is.
#' @return List or function, depending on the value of `render` (see above).
#' When returning an object of class `dash_component`, the default `print`
#' @return List or function, depending on the value of `render` (see above).
#' When returning an object of class `dash_component`, the default `print`
#' method for this class will display the corresponding pretty-printed JSON
#' representation of the object to the console.
layout_get = function(render = TRUE) {
Expand All@@ -739,7 +739,7 @@ Dash <- R6::R6Class(
#' class.
#' @param value An object of the `dash_component` class, which provides
#' a component or collection of components, specified either as a Dash
#' component or a function that returns a Dash component.
#' component or a function that returns a Dash component.
layout = function(value) {
# private$layout_ <- if (is.function(..1)) ..1 else list(...)
private$layout_ <- value
Expand DownExpand Up@@ -769,9 +769,9 @@ Dash <- R6::R6Class(
#' @description
#' Define a Dash callback.
#' @details
#' Describes a server or clientside callback relating the values of one or more
#' Describes a server or clientside callback relating the values of one or more
#' `output` items to one or more `input` items which will trigger the callback
#' when they change, and optionally `state` items which provide additional
#' when they change, and optionally `state` items which provide additional
#' information but do not trigger the callback directly.
#'
#' For detailed examples of how to use pattern-matching callbacks, see the
Expand All@@ -784,13 +784,13 @@ Dash <- R6::R6Class(
#' object(s) (which should reference layout components), which become
#' argument values for R callback handlers defined in `func`.
#'
#' Here `func` may either be an anonymous R function, a JavaScript function
#' Here `func` may either be an anonymous R function, a JavaScript function
#' provided as a character string, or a call to `clientsideFunction()`, which
#' describes a locally served JavaScript function instead. The latter
#' two methods define a "clientside callback", which updates components
#' without passing data to and from the Dash backend. The latter may offer
#' improved performance relative to callbacks written purely in R.
#' @param output Named list. The `output` argument provides the component `id`
#' @param output Named list. The `output` argument provides the component `id`
#' and `property` which will be updated by the callback; a callback can
#' target one or more outputs (i.e. multiple outputs).
#' @param params Unnamed list; provides [input] and [state] statements, each
Expand DownExpand Up@@ -852,12 +852,12 @@ Dash <- R6::R6Class(
#' the firing of a given callback, and allows introspection of the input/state
#' values given their names. It is only available from within a callback;
#' attempting to use this method outside of a callback will result in a warning.
#'
#'
#' The `callback_context` method returns a list containing three elements:
#' `states`, `triggered`, `inputs`. The first and last of these correspond to
#' the values of `states` and `inputs` for the current invocation of the
#' callback, and `triggered` provides a list of changed properties.
#'
#'
#' @return List comprising elements `states`, `triggered`, `inputs`.
callback_context = function() {
if (is.null(private$callback_context_)) {
Expand All@@ -877,14 +877,14 @@ Dash <- R6::R6Class(
#' duration required to execute a given callback. It may only be called
#' from within a callback; a warning will be thrown and the method will
#' otherwise return `NULL` if invoked outside of a callback.
#'
#'
#' @param name Character. The name of the resource.
#' @param duration Numeric. The time in seconds to report. Internally, this is
#' rounded to the nearest millisecond.
#' @param description Character. A description of the resource.
#'
callback_context.record_timing = function(name,
duration=NULL,
duration=NULL,
description=NULL) {
if (is.null(private$callback_context_)) {
warning("callback_context is undefined; callback_context.record_timing may only be accessed within a callback.")
Expand All@@ -897,7 +897,7 @@ Dash <- R6::R6Class(
stop(paste0("Duplicate resource name ", name, " found."), call.=FALSE)
}

timing_information[[name]] <- list("dur" = round(duration * 1000),
timing_information[[name]] <- list("dur" = round(duration * 1000),
"desc" = description)

self$server$set_data("timing-information", timing_information)
Expand All@@ -906,9 +906,9 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------------------
# return asset URLs
# ------------------------------------------------------------------------
#' @description
#' @description
#' Return a URL for a Dash asset.
#' @details
#' @details
#' The `get_asset_url` method permits retrieval of an asset's URL given its filename.
#' For example, `app$get_asset_url('style.css')` should return `/assets/style.css` when
#' `assets_folder = 'assets'`. By default, the prefix is the value of `requests_pathname_prefix`,
Expand DownExpand Up@@ -973,7 +973,7 @@ Dash <- R6::R6Class(
#' in components such as `dccLink` or `dccLocation`. For example, `app$get_relative_url("/page/")`
#' would return `/app/page/` for an app running on a deployment server. The path must be prefixed with
#' a `/`.
#' @param path Character. A path string prefixed with a leading `/` which directs
#' @param path Character. A path string prefixed with a leading `/` which directs
#' at a path or asset directory.
#' @param requests_pathname_prefix Character. The pathname prefix for the application when
#' deployed. Defaults to the environment variable set by the server,
Expand All@@ -984,12 +984,12 @@ Dash <- R6::R6Class(
asset = get_relative_path(requests_pathname = requests_pathname_prefix, path = path)
return(asset)
},


# ------------------------------------------------------------------------
# return relative asset URLs
# ------------------------------------------------------------------------

#' @description
#' Return a Dash asset path without its prefix.
#' @details
Expand All@@ -998,7 +998,7 @@ Dash <- R6::R6Class(
#' method, by taking a `relative path` as an input, and returning the `path` stripped of the `requests_pathname_prefix`,
#' and any leading or trailing `/`. For example, a path string `/app/homepage/`, would be returned as
#' `homepage`. This is particularly useful for `dccLocation` URL routing.
#' @param path Character. A path string prefixed with a leading `/` which directs
#' @param path Character. A path string prefixed with a leading `/` which directs
#' at a path or asset directory.
#' @param requests_pathname_prefix Character. The pathname prefix for the app on
#' a deployed application. Defaults to the environment variable set by the server,
Expand All@@ -1014,7 +1014,7 @@ Dash <- R6::R6Class(
#' Specify a custom index string for a Dash application.
#' @details
#' The `index_string` method allows the specification of a custom index by changing
#' the default `HTML` template that is generated by the Dash UI. #' Meta tags, CSS, and JavaScript are some examples of features
#' the default `HTML` template that is generated by the Dash UI. #' Meta tags, CSS, and 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
Expand DownExpand Up@@ -1054,11 +1054,11 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(string))
private$custom_index <- validate_keys(string, is_template=TRUE)
},

# ------------------------------------------------------------------------
# modify the templated variables by using the `interpolate_index` method.
# modify the templated variables by using the `interpolate_index` method.
# ------------------------------------------------------------------------
#' @description
#' @description
#' Modify index template variables for a Dash application.
#' @details
#' With the `interpolate_index` method, one can pass a custom index with template string
Expand DownExpand Up@@ -1087,14 +1087,14 @@ Dash <- R6::R6Class(
#' </footer>
#' </body>
#' </html>"
#'
#'

#' # this is the default configuration, but custom configurations
#' # are possible -- the structure of the "config" argument is
#' # a list, in which each element is a JSON key/value pair, when
#' # reformatted as JSON from the list:
#' # e.g. {"routes_pathname_prefix":"/", "ui":false}
#' config <- sprintf("<script id='_dash-config' type='application/json'> %s </script>",
#' config <- sprintf("<script id='_dash-config' type='application/json'> %s </script>",
#' jsonlite::toJSON(app$config, auto_unbox=TRUE))
#'
#' app$interpolate_index(
Expand All@@ -1107,17 +1107,17 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(template_index))
template <- template_index
kwargs <- list(...)

for (name in names(kwargs)) {
key = paste0('\\{\\%', name, '\\%\\}')
template = sub(key, kwargs[[name]], template)
}

}
invisible(validate_keys(names(kwargs), is_template=FALSE))

private$template_index <- template
},

# ------------------------------------------------------------------------
# specify a custom title
# ------------------------------------------------------------------------
Expand All@@ -1130,7 +1130,7 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(string))
private$name <- string
},

# ------------------------------------------------------------------------
# convenient fiery wrappers
# ------------------------------------------------------------------------
Expand All@@ -1155,7 +1155,7 @@ Dash <- R6::R6Class(
#' @param dev_tools_prune_errors Logical. Reduce tracebacks such that only lines relevant to user code remain, stripping out Fiery and Dash references? Only available with debugging. `TRUE` by default, set to `FALSE` to see the complete traceback. Environment variable: `DASH_PRUNE_ERRORS`.
#' @param dev_tools_silence_routes_logging Logical. Replace Fiery's default logger with `dashLogger` instead (will remove all routes logging)? Enabled with debugging by default because hot reload hash checks generate a lot of requests.
#' @param ... Additional arguments to pass to the `start` handler; see the [fiery] documentation for relevant examples.
#' @examples
#' @examples
#' if (interactive() && require(dash)) {
#' library(dashCoreComponents)
#' library(dashHtmlComponents)
Expand DownExpand Up@@ -1232,7 +1232,7 @@ Dash <- R6::R6Class(

# attach user-defined routes, if they exist
if (length(self$server$get_data("user-routes")) > 0) {

plugin <- list(
on_attach = function(server) {
user_routes <- server$get_data("user-routes")
Expand All@@ -1243,26 +1243,26 @@ Dash <- R6::R6Class(
# have all the relevant routes in place anyhow
if (server$plugins$request_routr$has_route("user-routes"))
server$plugins$request_routr$remove_route("user-routes")

router <- server$plugins$request_routr

route <- routr::Route$new()

for (routing in user_routes) {
route$add_handler(method=routing$methods,
path=routing$path,
handler=routing$handler)
}

router$add_route(route, "user-routes")
},
name = "user_routes",
require = "request_routr"
)

self$server$attach(plugin, force = TRUE)
}

if(getAppPath() != FALSE) {
source_dir <- dirname(getAppPath())
private$app_root_modtime <- modtimeFromPath(source_dir, recursive = TRUE, asset_path = private$assets_folder)
Expand DownExpand Up@@ -1304,7 +1304,7 @@ Dash <- R6::R6Class(
timing_information <- self$server$get_data('timing-information')
dash_total <- timing_information[['__dash_server']]
timing_information[['__dash_server']][['dur']] <- round((as.numeric(Sys.time()) - dash_total[['dur']]) * 1000)

header_as_string <- list()

for (item in seq_along(timing_information)) {
Expand All@@ -1317,11 +1317,11 @@ Dash <- R6::R6Class(
if (!is.null(timing_information[[item]]$dur)) {
header_content <- paste0(header_content, ';dur=', timing_information[[item]]$dur)
}

header_as_string[[item]] <- header_content
}

request$response$append_header('Server-Timing',
request$response$append_header('Server-Timing',
paste0(unlist(header_as_string), collapse=", "))
})
}
Expand DownExpand Up@@ -1443,7 +1443,7 @@ Dash <- R6::R6Class(
# flush the context to prepare for the next request cycle
self$server$set_data("timing-information", list())
})
}
}

self$server$ignite(block = block, showcase = showcase, ...)
}
Expand DownExpand Up@@ -1501,10 +1501,10 @@ Dash <- R6::R6Class(
layout_ids = NULL,
layout_render = function() {
layout_ <- if (is.function(private$layout_)) private$layout_() else private$layout_

# ensure that the layout is a component, or a collection of components
layout_ <- private$componentify(layout_)

# store the layout as a (flattened) vector form since we query the
# vector names several times to verify ID naming (among other things)
layout_flat <- rapply(layout_, I)
Expand All@@ -1518,7 +1518,7 @@ Dash <- R6::R6Class(

if (duped) {
duped_ids <- paste(layout_ids[duplicated(layout_ids)], collapse = ", ")

stop(
sprintf("layout ids must be unique -- please check the following list of duplicated ids: '%s'", duped_ids),
call. = FALSE
Expand DownExpand Up@@ -1942,21 +1942,21 @@ Dash <- R6::R6Class(

# 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
}
Expand Down
, '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('^' + ".*" + ' Revert "use correct non-vectorized version of logical and" by alexcjohnson · Pull Request #255 · plotly/dashR · GitHub
Skip to content
Merged
Changes from all commits
Commits
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
116 changes: 58 additions & 58 deletions R/dash.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,7 +50,7 @@ Dash <- R6::R6Class(
#' as `integrity` and `crossorigin`.
#' @param external_stylesheets List. An optional list of valid URLs from which
#' to serve CSS for rendered pages. Each entry can be a string (the URL) or a list
#' with `href` (the URL) and optionally other `<link>` tag attributes such as
#' with `href` (the URL) and optionally other `<link>` tag attributes such as
#' `rel`, `integrity` and `crossorigin`.
#' @param compress Logical. Whether to try to compress files and data served by Fiery.
#' By default, `brotli` is attempted first, then `gzip`, then the `deflate` algorithm,
Expand DownExpand Up@@ -116,9 +116,9 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------
router <- routr::RouteStack$new()
server$set_data("user-routes", list()) # placeholder for custom routes

# ensure that assets_folder is neither NULL nor character(0)
if (!(is.null(private$assets_folder)) && length(private$assets_folder) != 0) {
if (!(is.null(private$assets_folder)) & length(private$assets_folder) != 0) {
if (!(dir.exists(private$assets_folder)) && gsub("/+", "", assets_folder) != "assets") {
warning(sprintf(
"The supplied assets folder, '%s', could not be found in the project directory.",
Expand DownExpand Up@@ -618,9 +618,9 @@ Dash <- R6::R6Class(
#' library(dash)
#' app <- Dash$new()
#'
#' # A handler to redirect requests with `307` status code (temporary redirects);
#' # A handler to redirect requests with `307` status code (temporary redirects);
#' # for permanent redirects (`301`), see the `redirect` method described below
#' #
#' #
#' # A simple single path-to-path redirect
#' app$server_route('/getting-started', function(request, response, keys, ...) {
#' response$status <- 307L
Expand DownExpand Up@@ -653,11 +653,11 @@ Dash <- R6::R6Class(
"methods" = methods)

self$server$set_data("user-routes", user_routes)
},
},

#' @description
#' Redirect a Dash application URL path
#' @details
#' @details
#' This is a convenience method to simplify adding redirects
#' for your Dash application which automatically return a `301`
#' HTTP status code and direct the client to load an alternate URL.
Expand DownExpand Up@@ -705,7 +705,7 @@ Dash <- R6::R6Class(
TRUE
}
}

self$server_route(old_path, handler)
},

Expand All@@ -714,13 +714,13 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------------------
#' @description
#' Retrieves the Dash application layout.
#' @details
#' @details
#' If render is `TRUE`, and the layout is a function,
#' the result of the function (rather than the function itself) is returned.
#' @param render Logical. If the layout is a function, should the function be
#' executed to return the layout? If `FALSE`, the function is returned as-is.
#' @return List or function, depending on the value of `render` (see above).
#' When returning an object of class `dash_component`, the default `print`
#' @return List or function, depending on the value of `render` (see above).
#' When returning an object of class `dash_component`, the default `print`
#' method for this class will display the corresponding pretty-printed JSON
#' representation of the object to the console.
layout_get = function(render = TRUE) {
Expand All@@ -739,7 +739,7 @@ Dash <- R6::R6Class(
#' class.
#' @param value An object of the `dash_component` class, which provides
#' a component or collection of components, specified either as a Dash
#' component or a function that returns a Dash component.
#' component or a function that returns a Dash component.
layout = function(value) {
# private$layout_ <- if (is.function(..1)) ..1 else list(...)
private$layout_ <- value
Expand DownExpand Up@@ -769,9 +769,9 @@ Dash <- R6::R6Class(
#' @description
#' Define a Dash callback.
#' @details
#' Describes a server or clientside callback relating the values of one or more
#' Describes a server or clientside callback relating the values of one or more
#' `output` items to one or more `input` items which will trigger the callback
#' when they change, and optionally `state` items which provide additional
#' when they change, and optionally `state` items which provide additional
#' information but do not trigger the callback directly.
#'
#' For detailed examples of how to use pattern-matching callbacks, see the
Expand All@@ -784,13 +784,13 @@ Dash <- R6::R6Class(
#' object(s) (which should reference layout components), which become
#' argument values for R callback handlers defined in `func`.
#'
#' Here `func` may either be an anonymous R function, a JavaScript function
#' Here `func` may either be an anonymous R function, a JavaScript function
#' provided as a character string, or a call to `clientsideFunction()`, which
#' describes a locally served JavaScript function instead. The latter
#' two methods define a "clientside callback", which updates components
#' without passing data to and from the Dash backend. The latter may offer
#' improved performance relative to callbacks written purely in R.
#' @param output Named list. The `output` argument provides the component `id`
#' @param output Named list. The `output` argument provides the component `id`
#' and `property` which will be updated by the callback; a callback can
#' target one or more outputs (i.e. multiple outputs).
#' @param params Unnamed list; provides [input] and [state] statements, each
Expand DownExpand Up@@ -852,12 +852,12 @@ Dash <- R6::R6Class(
#' the firing of a given callback, and allows introspection of the input/state
#' values given their names. It is only available from within a callback;
#' attempting to use this method outside of a callback will result in a warning.
#'
#'
#' The `callback_context` method returns a list containing three elements:
#' `states`, `triggered`, `inputs`. The first and last of these correspond to
#' the values of `states` and `inputs` for the current invocation of the
#' callback, and `triggered` provides a list of changed properties.
#'
#'
#' @return List comprising elements `states`, `triggered`, `inputs`.
callback_context = function() {
if (is.null(private$callback_context_)) {
Expand All@@ -877,14 +877,14 @@ Dash <- R6::R6Class(
#' duration required to execute a given callback. It may only be called
#' from within a callback; a warning will be thrown and the method will
#' otherwise return `NULL` if invoked outside of a callback.
#'
#'
#' @param name Character. The name of the resource.
#' @param duration Numeric. The time in seconds to report. Internally, this is
#' rounded to the nearest millisecond.
#' @param description Character. A description of the resource.
#'
callback_context.record_timing = function(name,
duration=NULL,
duration=NULL,
description=NULL) {
if (is.null(private$callback_context_)) {
warning("callback_context is undefined; callback_context.record_timing may only be accessed within a callback.")
Expand All@@ -897,7 +897,7 @@ Dash <- R6::R6Class(
stop(paste0("Duplicate resource name ", name, " found."), call.=FALSE)
}

timing_information[[name]] <- list("dur" = round(duration * 1000),
timing_information[[name]] <- list("dur" = round(duration * 1000),
"desc" = description)

self$server$set_data("timing-information", timing_information)
Expand All@@ -906,9 +906,9 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------------------
# return asset URLs
# ------------------------------------------------------------------------
#' @description
#' @description
#' Return a URL for a Dash asset.
#' @details
#' @details
#' The `get_asset_url` method permits retrieval of an asset's URL given its filename.
#' For example, `app$get_asset_url('style.css')` should return `/assets/style.css` when
#' `assets_folder = 'assets'`. By default, the prefix is the value of `requests_pathname_prefix`,
Expand DownExpand Up@@ -973,7 +973,7 @@ Dash <- R6::R6Class(
#' in components such as `dccLink` or `dccLocation`. For example, `app$get_relative_url("/page/")`
#' would return `/app/page/` for an app running on a deployment server. The path must be prefixed with
#' a `/`.
#' @param path Character. A path string prefixed with a leading `/` which directs
#' @param path Character. A path string prefixed with a leading `/` which directs
#' at a path or asset directory.
#' @param requests_pathname_prefix Character. The pathname prefix for the application when
#' deployed. Defaults to the environment variable set by the server,
Expand All@@ -984,12 +984,12 @@ Dash <- R6::R6Class(
asset = get_relative_path(requests_pathname = requests_pathname_prefix, path = path)
return(asset)
},


# ------------------------------------------------------------------------
# return relative asset URLs
# ------------------------------------------------------------------------

#' @description
#' Return a Dash asset path without its prefix.
#' @details
Expand All@@ -998,7 +998,7 @@ Dash <- R6::R6Class(
#' method, by taking a `relative path` as an input, and returning the `path` stripped of the `requests_pathname_prefix`,
#' and any leading or trailing `/`. For example, a path string `/app/homepage/`, would be returned as
#' `homepage`. This is particularly useful for `dccLocation` URL routing.
#' @param path Character. A path string prefixed with a leading `/` which directs
#' @param path Character. A path string prefixed with a leading `/` which directs
#' at a path or asset directory.
#' @param requests_pathname_prefix Character. The pathname prefix for the app on
#' a deployed application. Defaults to the environment variable set by the server,
Expand All@@ -1014,7 +1014,7 @@ Dash <- R6::R6Class(
#' Specify a custom index string for a Dash application.
#' @details
#' The `index_string` method allows the specification of a custom index by changing
#' the default `HTML` template that is generated by the Dash UI. #' Meta tags, CSS, and JavaScript are some examples of features
#' the default `HTML` template that is generated by the Dash UI. #' Meta tags, CSS, and 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
Expand DownExpand Up@@ -1054,11 +1054,11 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(string))
private$custom_index <- validate_keys(string, is_template=TRUE)
},

# ------------------------------------------------------------------------
# modify the templated variables by using the `interpolate_index` method.
# modify the templated variables by using the `interpolate_index` method.
# ------------------------------------------------------------------------
#' @description
#' @description
#' Modify index template variables for a Dash application.
#' @details
#' With the `interpolate_index` method, one can pass a custom index with template string
Expand DownExpand Up@@ -1087,14 +1087,14 @@ Dash <- R6::R6Class(
#' </footer>
#' </body>
#' </html>"
#'
#'

#' # this is the default configuration, but custom configurations
#' # are possible -- the structure of the "config" argument is
#' # a list, in which each element is a JSON key/value pair, when
#' # reformatted as JSON from the list:
#' # e.g. {"routes_pathname_prefix":"/", "ui":false}
#' config <- sprintf("<script id='_dash-config' type='application/json'> %s </script>",
#' config <- sprintf("<script id='_dash-config' type='application/json'> %s </script>",
#' jsonlite::toJSON(app$config, auto_unbox=TRUE))
#'
#' app$interpolate_index(
Expand All@@ -1107,17 +1107,17 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(template_index))
template <- template_index
kwargs <- list(...)

for (name in names(kwargs)) {
key = paste0('\\{\\%', name, '\\%\\}')
template = sub(key, kwargs[[name]], template)
}

}
invisible(validate_keys(names(kwargs), is_template=FALSE))

private$template_index <- template
},

# ------------------------------------------------------------------------
# specify a custom title
# ------------------------------------------------------------------------
Expand All@@ -1130,7 +1130,7 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(string))
private$name <- string
},

# ------------------------------------------------------------------------
# convenient fiery wrappers
# ------------------------------------------------------------------------
Expand All@@ -1155,7 +1155,7 @@ Dash <- R6::R6Class(
#' @param dev_tools_prune_errors Logical. Reduce tracebacks such that only lines relevant to user code remain, stripping out Fiery and Dash references? Only available with debugging. `TRUE` by default, set to `FALSE` to see the complete traceback. Environment variable: `DASH_PRUNE_ERRORS`.
#' @param dev_tools_silence_routes_logging Logical. Replace Fiery's default logger with `dashLogger` instead (will remove all routes logging)? Enabled with debugging by default because hot reload hash checks generate a lot of requests.
#' @param ... Additional arguments to pass to the `start` handler; see the [fiery] documentation for relevant examples.
#' @examples
#' @examples
#' if (interactive() && require(dash)) {
#' library(dashCoreComponents)
#' library(dashHtmlComponents)
Expand DownExpand Up@@ -1232,7 +1232,7 @@ Dash <- R6::R6Class(

# attach user-defined routes, if they exist
if (length(self$server$get_data("user-routes")) > 0) {

plugin <- list(
on_attach = function(server) {
user_routes <- server$get_data("user-routes")
Expand All@@ -1243,26 +1243,26 @@ Dash <- R6::R6Class(
# have all the relevant routes in place anyhow
if (server$plugins$request_routr$has_route("user-routes"))
server$plugins$request_routr$remove_route("user-routes")

router <- server$plugins$request_routr

route <- routr::Route$new()

for (routing in user_routes) {
route$add_handler(method=routing$methods,
path=routing$path,
handler=routing$handler)
}

router$add_route(route, "user-routes")
},
name = "user_routes",
require = "request_routr"
)

self$server$attach(plugin, force = TRUE)
}

if(getAppPath() != FALSE) {
source_dir <- dirname(getAppPath())
private$app_root_modtime <- modtimeFromPath(source_dir, recursive = TRUE, asset_path = private$assets_folder)
Expand DownExpand Up@@ -1304,7 +1304,7 @@ Dash <- R6::R6Class(
timing_information <- self$server$get_data('timing-information')
dash_total <- timing_information[['__dash_server']]
timing_information[['__dash_server']][['dur']] <- round((as.numeric(Sys.time()) - dash_total[['dur']]) * 1000)

header_as_string <- list()

for (item in seq_along(timing_information)) {
Expand All@@ -1317,11 +1317,11 @@ Dash <- R6::R6Class(
if (!is.null(timing_information[[item]]$dur)) {
header_content <- paste0(header_content, ';dur=', timing_information[[item]]$dur)
}

header_as_string[[item]] <- header_content
}

request$response$append_header('Server-Timing',
request$response$append_header('Server-Timing',
paste0(unlist(header_as_string), collapse=", "))
})
}
Expand DownExpand Up@@ -1443,7 +1443,7 @@ Dash <- R6::R6Class(
# flush the context to prepare for the next request cycle
self$server$set_data("timing-information", list())
})
}
}

self$server$ignite(block = block, showcase = showcase, ...)
}
Expand DownExpand Up@@ -1501,10 +1501,10 @@ Dash <- R6::R6Class(
layout_ids = NULL,
layout_render = function() {
layout_ <- if (is.function(private$layout_)) private$layout_() else private$layout_

# ensure that the layout is a component, or a collection of components
layout_ <- private$componentify(layout_)

# store the layout as a (flattened) vector form since we query the
# vector names several times to verify ID naming (among other things)
layout_flat <- rapply(layout_, I)
Expand All@@ -1518,7 +1518,7 @@ Dash <- R6::R6Class(

if (duped) {
duped_ids <- paste(layout_ids[duplicated(layout_ids)], collapse = ", ")

stop(
sprintf("layout ids must be unique -- please check the following list of duplicated ids: '%s'", duped_ids),
call. = FALSE
Expand DownExpand Up@@ -1942,21 +1942,21 @@ Dash <- R6::R6Class(

# 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
}
Expand Down
, '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" + ' Revert "use correct non-vectorized version of logical and" by alexcjohnson · Pull Request #255 · plotly/dashR · GitHub
Skip to content
Merged
Changes from all commits
Commits
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
116 changes: 58 additions & 58 deletions R/dash.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,7 +50,7 @@ Dash <- R6::R6Class(
#' as `integrity` and `crossorigin`.
#' @param external_stylesheets List. An optional list of valid URLs from which
#' to serve CSS for rendered pages. Each entry can be a string (the URL) or a list
#' with `href` (the URL) and optionally other `<link>` tag attributes such as
#' with `href` (the URL) and optionally other `<link>` tag attributes such as
#' `rel`, `integrity` and `crossorigin`.
#' @param compress Logical. Whether to try to compress files and data served by Fiery.
#' By default, `brotli` is attempted first, then `gzip`, then the `deflate` algorithm,
Expand DownExpand Up@@ -116,9 +116,9 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------
router <- routr::RouteStack$new()
server$set_data("user-routes", list()) # placeholder for custom routes

# ensure that assets_folder is neither NULL nor character(0)
if (!(is.null(private$assets_folder)) && length(private$assets_folder) != 0) {
if (!(is.null(private$assets_folder)) & length(private$assets_folder) != 0) {
if (!(dir.exists(private$assets_folder)) && gsub("/+", "", assets_folder) != "assets") {
warning(sprintf(
"The supplied assets folder, '%s', could not be found in the project directory.",
Expand DownExpand Up@@ -618,9 +618,9 @@ Dash <- R6::R6Class(
#' library(dash)
#' app <- Dash$new()
#'
#' # A handler to redirect requests with `307` status code (temporary redirects);
#' # A handler to redirect requests with `307` status code (temporary redirects);
#' # for permanent redirects (`301`), see the `redirect` method described below
#' #
#' #
#' # A simple single path-to-path redirect
#' app$server_route('/getting-started', function(request, response, keys, ...) {
#' response$status <- 307L
Expand DownExpand Up@@ -653,11 +653,11 @@ Dash <- R6::R6Class(
"methods" = methods)

self$server$set_data("user-routes", user_routes)
},
},

#' @description
#' Redirect a Dash application URL path
#' @details
#' @details
#' This is a convenience method to simplify adding redirects
#' for your Dash application which automatically return a `301`
#' HTTP status code and direct the client to load an alternate URL.
Expand DownExpand Up@@ -705,7 +705,7 @@ Dash <- R6::R6Class(
TRUE
}
}

self$server_route(old_path, handler)
},

Expand All@@ -714,13 +714,13 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------------------
#' @description
#' Retrieves the Dash application layout.
#' @details
#' @details
#' If render is `TRUE`, and the layout is a function,
#' the result of the function (rather than the function itself) is returned.
#' @param render Logical. If the layout is a function, should the function be
#' executed to return the layout? If `FALSE`, the function is returned as-is.
#' @return List or function, depending on the value of `render` (see above).
#' When returning an object of class `dash_component`, the default `print`
#' @return List or function, depending on the value of `render` (see above).
#' When returning an object of class `dash_component`, the default `print`
#' method for this class will display the corresponding pretty-printed JSON
#' representation of the object to the console.
layout_get = function(render = TRUE) {
Expand All@@ -739,7 +739,7 @@ Dash <- R6::R6Class(
#' class.
#' @param value An object of the `dash_component` class, which provides
#' a component or collection of components, specified either as a Dash
#' component or a function that returns a Dash component.
#' component or a function that returns a Dash component.
layout = function(value) {
# private$layout_ <- if (is.function(..1)) ..1 else list(...)
private$layout_ <- value
Expand DownExpand Up@@ -769,9 +769,9 @@ Dash <- R6::R6Class(
#' @description
#' Define a Dash callback.
#' @details
#' Describes a server or clientside callback relating the values of one or more
#' Describes a server or clientside callback relating the values of one or more
#' `output` items to one or more `input` items which will trigger the callback
#' when they change, and optionally `state` items which provide additional
#' when they change, and optionally `state` items which provide additional
#' information but do not trigger the callback directly.
#'
#' For detailed examples of how to use pattern-matching callbacks, see the
Expand All@@ -784,13 +784,13 @@ Dash <- R6::R6Class(
#' object(s) (which should reference layout components), which become
#' argument values for R callback handlers defined in `func`.
#'
#' Here `func` may either be an anonymous R function, a JavaScript function
#' Here `func` may either be an anonymous R function, a JavaScript function
#' provided as a character string, or a call to `clientsideFunction()`, which
#' describes a locally served JavaScript function instead. The latter
#' two methods define a "clientside callback", which updates components
#' without passing data to and from the Dash backend. The latter may offer
#' improved performance relative to callbacks written purely in R.
#' @param output Named list. The `output` argument provides the component `id`
#' @param output Named list. The `output` argument provides the component `id`
#' and `property` which will be updated by the callback; a callback can
#' target one or more outputs (i.e. multiple outputs).
#' @param params Unnamed list; provides [input] and [state] statements, each
Expand DownExpand Up@@ -852,12 +852,12 @@ Dash <- R6::R6Class(
#' the firing of a given callback, and allows introspection of the input/state
#' values given their names. It is only available from within a callback;
#' attempting to use this method outside of a callback will result in a warning.
#'
#'
#' The `callback_context` method returns a list containing three elements:
#' `states`, `triggered`, `inputs`. The first and last of these correspond to
#' the values of `states` and `inputs` for the current invocation of the
#' callback, and `triggered` provides a list of changed properties.
#'
#'
#' @return List comprising elements `states`, `triggered`, `inputs`.
callback_context = function() {
if (is.null(private$callback_context_)) {
Expand All@@ -877,14 +877,14 @@ Dash <- R6::R6Class(
#' duration required to execute a given callback. It may only be called
#' from within a callback; a warning will be thrown and the method will
#' otherwise return `NULL` if invoked outside of a callback.
#'
#'
#' @param name Character. The name of the resource.
#' @param duration Numeric. The time in seconds to report. Internally, this is
#' rounded to the nearest millisecond.
#' @param description Character. A description of the resource.
#'
callback_context.record_timing = function(name,
duration=NULL,
duration=NULL,
description=NULL) {
if (is.null(private$callback_context_)) {
warning("callback_context is undefined; callback_context.record_timing may only be accessed within a callback.")
Expand All@@ -897,7 +897,7 @@ Dash <- R6::R6Class(
stop(paste0("Duplicate resource name ", name, " found."), call.=FALSE)
}

timing_information[[name]] <- list("dur" = round(duration * 1000),
timing_information[[name]] <- list("dur" = round(duration * 1000),
"desc" = description)

self$server$set_data("timing-information", timing_information)
Expand All@@ -906,9 +906,9 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------------------
# return asset URLs
# ------------------------------------------------------------------------
#' @description
#' @description
#' Return a URL for a Dash asset.
#' @details
#' @details
#' The `get_asset_url` method permits retrieval of an asset's URL given its filename.
#' For example, `app$get_asset_url('style.css')` should return `/assets/style.css` when
#' `assets_folder = 'assets'`. By default, the prefix is the value of `requests_pathname_prefix`,
Expand DownExpand Up@@ -973,7 +973,7 @@ Dash <- R6::R6Class(
#' in components such as `dccLink` or `dccLocation`. For example, `app$get_relative_url("/page/")`
#' would return `/app/page/` for an app running on a deployment server. The path must be prefixed with
#' a `/`.
#' @param path Character. A path string prefixed with a leading `/` which directs
#' @param path Character. A path string prefixed with a leading `/` which directs
#' at a path or asset directory.
#' @param requests_pathname_prefix Character. The pathname prefix for the application when
#' deployed. Defaults to the environment variable set by the server,
Expand All@@ -984,12 +984,12 @@ Dash <- R6::R6Class(
asset = get_relative_path(requests_pathname = requests_pathname_prefix, path = path)
return(asset)
},


# ------------------------------------------------------------------------
# return relative asset URLs
# ------------------------------------------------------------------------

#' @description
#' Return a Dash asset path without its prefix.
#' @details
Expand All@@ -998,7 +998,7 @@ Dash <- R6::R6Class(
#' method, by taking a `relative path` as an input, and returning the `path` stripped of the `requests_pathname_prefix`,
#' and any leading or trailing `/`. For example, a path string `/app/homepage/`, would be returned as
#' `homepage`. This is particularly useful for `dccLocation` URL routing.
#' @param path Character. A path string prefixed with a leading `/` which directs
#' @param path Character. A path string prefixed with a leading `/` which directs
#' at a path or asset directory.
#' @param requests_pathname_prefix Character. The pathname prefix for the app on
#' a deployed application. Defaults to the environment variable set by the server,
Expand All@@ -1014,7 +1014,7 @@ Dash <- R6::R6Class(
#' Specify a custom index string for a Dash application.
#' @details
#' The `index_string` method allows the specification of a custom index by changing
#' the default `HTML` template that is generated by the Dash UI. #' Meta tags, CSS, and JavaScript are some examples of features
#' the default `HTML` template that is generated by the Dash UI. #' Meta tags, CSS, and 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
Expand DownExpand Up@@ -1054,11 +1054,11 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(string))
private$custom_index <- validate_keys(string, is_template=TRUE)
},

# ------------------------------------------------------------------------
# modify the templated variables by using the `interpolate_index` method.
# modify the templated variables by using the `interpolate_index` method.
# ------------------------------------------------------------------------
#' @description
#' @description
#' Modify index template variables for a Dash application.
#' @details
#' With the `interpolate_index` method, one can pass a custom index with template string
Expand DownExpand Up@@ -1087,14 +1087,14 @@ Dash <- R6::R6Class(
#' </footer>
#' </body>
#' </html>"
#'
#'

#' # this is the default configuration, but custom configurations
#' # are possible -- the structure of the "config" argument is
#' # a list, in which each element is a JSON key/value pair, when
#' # reformatted as JSON from the list:
#' # e.g. {"routes_pathname_prefix":"/", "ui":false}
#' config <- sprintf("<script id='_dash-config' type='application/json'> %s </script>",
#' config <- sprintf("<script id='_dash-config' type='application/json'> %s </script>",
#' jsonlite::toJSON(app$config, auto_unbox=TRUE))
#'
#' app$interpolate_index(
Expand All@@ -1107,17 +1107,17 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(template_index))
template <- template_index
kwargs <- list(...)

for (name in names(kwargs)) {
key = paste0('\\{\\%', name, '\\%\\}')
template = sub(key, kwargs[[name]], template)
}

}
invisible(validate_keys(names(kwargs), is_template=FALSE))

private$template_index <- template
},

# ------------------------------------------------------------------------
# specify a custom title
# ------------------------------------------------------------------------
Expand All@@ -1130,7 +1130,7 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(string))
private$name <- string
},

# ------------------------------------------------------------------------
# convenient fiery wrappers
# ------------------------------------------------------------------------
Expand All@@ -1155,7 +1155,7 @@ Dash <- R6::R6Class(
#' @param dev_tools_prune_errors Logical. Reduce tracebacks such that only lines relevant to user code remain, stripping out Fiery and Dash references? Only available with debugging. `TRUE` by default, set to `FALSE` to see the complete traceback. Environment variable: `DASH_PRUNE_ERRORS`.
#' @param dev_tools_silence_routes_logging Logical. Replace Fiery's default logger with `dashLogger` instead (will remove all routes logging)? Enabled with debugging by default because hot reload hash checks generate a lot of requests.
#' @param ... Additional arguments to pass to the `start` handler; see the [fiery] documentation for relevant examples.
#' @examples
#' @examples
#' if (interactive() && require(dash)) {
#' library(dashCoreComponents)
#' library(dashHtmlComponents)
Expand DownExpand Up@@ -1232,7 +1232,7 @@ Dash <- R6::R6Class(

# attach user-defined routes, if they exist
if (length(self$server$get_data("user-routes")) > 0) {

plugin <- list(
on_attach = function(server) {
user_routes <- server$get_data("user-routes")
Expand All@@ -1243,26 +1243,26 @@ Dash <- R6::R6Class(
# have all the relevant routes in place anyhow
if (server$plugins$request_routr$has_route("user-routes"))
server$plugins$request_routr$remove_route("user-routes")

router <- server$plugins$request_routr

route <- routr::Route$new()

for (routing in user_routes) {
route$add_handler(method=routing$methods,
path=routing$path,
handler=routing$handler)
}

router$add_route(route, "user-routes")
},
name = "user_routes",
require = "request_routr"
)

self$server$attach(plugin, force = TRUE)
}

if(getAppPath() != FALSE) {
source_dir <- dirname(getAppPath())
private$app_root_modtime <- modtimeFromPath(source_dir, recursive = TRUE, asset_path = private$assets_folder)
Expand DownExpand Up@@ -1304,7 +1304,7 @@ Dash <- R6::R6Class(
timing_information <- self$server$get_data('timing-information')
dash_total <- timing_information[['__dash_server']]
timing_information[['__dash_server']][['dur']] <- round((as.numeric(Sys.time()) - dash_total[['dur']]) * 1000)

header_as_string <- list()

for (item in seq_along(timing_information)) {
Expand All@@ -1317,11 +1317,11 @@ Dash <- R6::R6Class(
if (!is.null(timing_information[[item]]$dur)) {
header_content <- paste0(header_content, ';dur=', timing_information[[item]]$dur)
}

header_as_string[[item]] <- header_content
}

request$response$append_header('Server-Timing',
request$response$append_header('Server-Timing',
paste0(unlist(header_as_string), collapse=", "))
})
}
Expand DownExpand Up@@ -1443,7 +1443,7 @@ Dash <- R6::R6Class(
# flush the context to prepare for the next request cycle
self$server$set_data("timing-information", list())
})
}
}

self$server$ignite(block = block, showcase = showcase, ...)
}
Expand DownExpand Up@@ -1501,10 +1501,10 @@ Dash <- R6::R6Class(
layout_ids = NULL,
layout_render = function() {
layout_ <- if (is.function(private$layout_)) private$layout_() else private$layout_

# ensure that the layout is a component, or a collection of components
layout_ <- private$componentify(layout_)

# store the layout as a (flattened) vector form since we query the
# vector names several times to verify ID naming (among other things)
layout_flat <- rapply(layout_, I)
Expand All@@ -1518,7 +1518,7 @@ Dash <- R6::R6Class(

if (duped) {
duped_ids <- paste(layout_ids[duplicated(layout_ids)], collapse = ", ")

stop(
sprintf("layout ids must be unique -- please check the following list of duplicated ids: '%s'", duped_ids),
call. = FALSE
Expand DownExpand Up@@ -1942,21 +1942,21 @@ Dash <- R6::R6Class(

# 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
}
Expand Down
, '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('^' + ".*" + ' Revert "use correct non-vectorized version of logical and" by alexcjohnson · Pull Request #255 · plotly/dashR · GitHub
Skip to content
Merged
Changes from all commits
Commits
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
116 changes: 58 additions & 58 deletions R/dash.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,7 +50,7 @@ Dash <- R6::R6Class(
#' as `integrity` and `crossorigin`.
#' @param external_stylesheets List. An optional list of valid URLs from which
#' to serve CSS for rendered pages. Each entry can be a string (the URL) or a list
#' with `href` (the URL) and optionally other `<link>` tag attributes such as
#' with `href` (the URL) and optionally other `<link>` tag attributes such as
#' `rel`, `integrity` and `crossorigin`.
#' @param compress Logical. Whether to try to compress files and data served by Fiery.
#' By default, `brotli` is attempted first, then `gzip`, then the `deflate` algorithm,
Expand DownExpand Up@@ -116,9 +116,9 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------
router <- routr::RouteStack$new()
server$set_data("user-routes", list()) # placeholder for custom routes

# ensure that assets_folder is neither NULL nor character(0)
if (!(is.null(private$assets_folder)) && length(private$assets_folder) != 0) {
if (!(is.null(private$assets_folder)) & length(private$assets_folder) != 0) {
if (!(dir.exists(private$assets_folder)) && gsub("/+", "", assets_folder) != "assets") {
warning(sprintf(
"The supplied assets folder, '%s', could not be found in the project directory.",
Expand DownExpand Up@@ -618,9 +618,9 @@ Dash <- R6::R6Class(
#' library(dash)
#' app <- Dash$new()
#'
#' # A handler to redirect requests with `307` status code (temporary redirects);
#' # A handler to redirect requests with `307` status code (temporary redirects);
#' # for permanent redirects (`301`), see the `redirect` method described below
#' #
#' #
#' # A simple single path-to-path redirect
#' app$server_route('/getting-started', function(request, response, keys, ...) {
#' response$status <- 307L
Expand DownExpand Up@@ -653,11 +653,11 @@ Dash <- R6::R6Class(
"methods" = methods)

self$server$set_data("user-routes", user_routes)
},
},

#' @description
#' Redirect a Dash application URL path
#' @details
#' @details
#' This is a convenience method to simplify adding redirects
#' for your Dash application which automatically return a `301`
#' HTTP status code and direct the client to load an alternate URL.
Expand DownExpand Up@@ -705,7 +705,7 @@ Dash <- R6::R6Class(
TRUE
}
}

self$server_route(old_path, handler)
},

Expand All@@ -714,13 +714,13 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------------------
#' @description
#' Retrieves the Dash application layout.
#' @details
#' @details
#' If render is `TRUE`, and the layout is a function,
#' the result of the function (rather than the function itself) is returned.
#' @param render Logical. If the layout is a function, should the function be
#' executed to return the layout? If `FALSE`, the function is returned as-is.
#' @return List or function, depending on the value of `render` (see above).
#' When returning an object of class `dash_component`, the default `print`
#' @return List or function, depending on the value of `render` (see above).
#' When returning an object of class `dash_component`, the default `print`
#' method for this class will display the corresponding pretty-printed JSON
#' representation of the object to the console.
layout_get = function(render = TRUE) {
Expand All@@ -739,7 +739,7 @@ Dash <- R6::R6Class(
#' class.
#' @param value An object of the `dash_component` class, which provides
#' a component or collection of components, specified either as a Dash
#' component or a function that returns a Dash component.
#' component or a function that returns a Dash component.
layout = function(value) {
# private$layout_ <- if (is.function(..1)) ..1 else list(...)
private$layout_ <- value
Expand DownExpand Up@@ -769,9 +769,9 @@ Dash <- R6::R6Class(
#' @description
#' Define a Dash callback.
#' @details
#' Describes a server or clientside callback relating the values of one or more
#' Describes a server or clientside callback relating the values of one or more
#' `output` items to one or more `input` items which will trigger the callback
#' when they change, and optionally `state` items which provide additional
#' when they change, and optionally `state` items which provide additional
#' information but do not trigger the callback directly.
#'
#' For detailed examples of how to use pattern-matching callbacks, see the
Expand All@@ -784,13 +784,13 @@ Dash <- R6::R6Class(
#' object(s) (which should reference layout components), which become
#' argument values for R callback handlers defined in `func`.
#'
#' Here `func` may either be an anonymous R function, a JavaScript function
#' Here `func` may either be an anonymous R function, a JavaScript function
#' provided as a character string, or a call to `clientsideFunction()`, which
#' describes a locally served JavaScript function instead. The latter
#' two methods define a "clientside callback", which updates components
#' without passing data to and from the Dash backend. The latter may offer
#' improved performance relative to callbacks written purely in R.
#' @param output Named list. The `output` argument provides the component `id`
#' @param output Named list. The `output` argument provides the component `id`
#' and `property` which will be updated by the callback; a callback can
#' target one or more outputs (i.e. multiple outputs).
#' @param params Unnamed list; provides [input] and [state] statements, each
Expand DownExpand Up@@ -852,12 +852,12 @@ Dash <- R6::R6Class(
#' the firing of a given callback, and allows introspection of the input/state
#' values given their names. It is only available from within a callback;
#' attempting to use this method outside of a callback will result in a warning.
#'
#'
#' The `callback_context` method returns a list containing three elements:
#' `states`, `triggered`, `inputs`. The first and last of these correspond to
#' the values of `states` and `inputs` for the current invocation of the
#' callback, and `triggered` provides a list of changed properties.
#'
#'
#' @return List comprising elements `states`, `triggered`, `inputs`.
callback_context = function() {
if (is.null(private$callback_context_)) {
Expand All@@ -877,14 +877,14 @@ Dash <- R6::R6Class(
#' duration required to execute a given callback. It may only be called
#' from within a callback; a warning will be thrown and the method will
#' otherwise return `NULL` if invoked outside of a callback.
#'
#'
#' @param name Character. The name of the resource.
#' @param duration Numeric. The time in seconds to report. Internally, this is
#' rounded to the nearest millisecond.
#' @param description Character. A description of the resource.
#'
callback_context.record_timing = function(name,
duration=NULL,
duration=NULL,
description=NULL) {
if (is.null(private$callback_context_)) {
warning("callback_context is undefined; callback_context.record_timing may only be accessed within a callback.")
Expand All@@ -897,7 +897,7 @@ Dash <- R6::R6Class(
stop(paste0("Duplicate resource name ", name, " found."), call.=FALSE)
}

timing_information[[name]] <- list("dur" = round(duration * 1000),
timing_information[[name]] <- list("dur" = round(duration * 1000),
"desc" = description)

self$server$set_data("timing-information", timing_information)
Expand All@@ -906,9 +906,9 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------------------
# return asset URLs
# ------------------------------------------------------------------------
#' @description
#' @description
#' Return a URL for a Dash asset.
#' @details
#' @details
#' The `get_asset_url` method permits retrieval of an asset's URL given its filename.
#' For example, `app$get_asset_url('style.css')` should return `/assets/style.css` when
#' `assets_folder = 'assets'`. By default, the prefix is the value of `requests_pathname_prefix`,
Expand DownExpand Up@@ -973,7 +973,7 @@ Dash <- R6::R6Class(
#' in components such as `dccLink` or `dccLocation`. For example, `app$get_relative_url("/page/")`
#' would return `/app/page/` for an app running on a deployment server. The path must be prefixed with
#' a `/`.
#' @param path Character. A path string prefixed with a leading `/` which directs
#' @param path Character. A path string prefixed with a leading `/` which directs
#' at a path or asset directory.
#' @param requests_pathname_prefix Character. The pathname prefix for the application when
#' deployed. Defaults to the environment variable set by the server,
Expand All@@ -984,12 +984,12 @@ Dash <- R6::R6Class(
asset = get_relative_path(requests_pathname = requests_pathname_prefix, path = path)
return(asset)
},


# ------------------------------------------------------------------------
# return relative asset URLs
# ------------------------------------------------------------------------

#' @description
#' Return a Dash asset path without its prefix.
#' @details
Expand All@@ -998,7 +998,7 @@ Dash <- R6::R6Class(
#' method, by taking a `relative path` as an input, and returning the `path` stripped of the `requests_pathname_prefix`,
#' and any leading or trailing `/`. For example, a path string `/app/homepage/`, would be returned as
#' `homepage`. This is particularly useful for `dccLocation` URL routing.
#' @param path Character. A path string prefixed with a leading `/` which directs
#' @param path Character. A path string prefixed with a leading `/` which directs
#' at a path or asset directory.
#' @param requests_pathname_prefix Character. The pathname prefix for the app on
#' a deployed application. Defaults to the environment variable set by the server,
Expand All@@ -1014,7 +1014,7 @@ Dash <- R6::R6Class(
#' Specify a custom index string for a Dash application.
#' @details
#' The `index_string` method allows the specification of a custom index by changing
#' the default `HTML` template that is generated by the Dash UI. #' Meta tags, CSS, and JavaScript are some examples of features
#' the default `HTML` template that is generated by the Dash UI. #' Meta tags, CSS, and 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
Expand DownExpand Up@@ -1054,11 +1054,11 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(string))
private$custom_index <- validate_keys(string, is_template=TRUE)
},

# ------------------------------------------------------------------------
# modify the templated variables by using the `interpolate_index` method.
# modify the templated variables by using the `interpolate_index` method.
# ------------------------------------------------------------------------
#' @description
#' @description
#' Modify index template variables for a Dash application.
#' @details
#' With the `interpolate_index` method, one can pass a custom index with template string
Expand DownExpand Up@@ -1087,14 +1087,14 @@ Dash <- R6::R6Class(
#' </footer>
#' </body>
#' </html>"
#'
#'

#' # this is the default configuration, but custom configurations
#' # are possible -- the structure of the "config" argument is
#' # a list, in which each element is a JSON key/value pair, when
#' # reformatted as JSON from the list:
#' # e.g. {"routes_pathname_prefix":"/", "ui":false}
#' config <- sprintf("<script id='_dash-config' type='application/json'> %s </script>",
#' config <- sprintf("<script id='_dash-config' type='application/json'> %s </script>",
#' jsonlite::toJSON(app$config, auto_unbox=TRUE))
#'
#' app$interpolate_index(
Expand All@@ -1107,17 +1107,17 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(template_index))
template <- template_index
kwargs <- list(...)

for (name in names(kwargs)) {
key = paste0('\\{\\%', name, '\\%\\}')
template = sub(key, kwargs[[name]], template)
}

}
invisible(validate_keys(names(kwargs), is_template=FALSE))

private$template_index <- template
},

# ------------------------------------------------------------------------
# specify a custom title
# ------------------------------------------------------------------------
Expand All@@ -1130,7 +1130,7 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(string))
private$name <- string
},

# ------------------------------------------------------------------------
# convenient fiery wrappers
# ------------------------------------------------------------------------
Expand All@@ -1155,7 +1155,7 @@ Dash <- R6::R6Class(
#' @param dev_tools_prune_errors Logical. Reduce tracebacks such that only lines relevant to user code remain, stripping out Fiery and Dash references? Only available with debugging. `TRUE` by default, set to `FALSE` to see the complete traceback. Environment variable: `DASH_PRUNE_ERRORS`.
#' @param dev_tools_silence_routes_logging Logical. Replace Fiery's default logger with `dashLogger` instead (will remove all routes logging)? Enabled with debugging by default because hot reload hash checks generate a lot of requests.
#' @param ... Additional arguments to pass to the `start` handler; see the [fiery] documentation for relevant examples.
#' @examples
#' @examples
#' if (interactive() && require(dash)) {
#' library(dashCoreComponents)
#' library(dashHtmlComponents)
Expand DownExpand Up@@ -1232,7 +1232,7 @@ Dash <- R6::R6Class(

# attach user-defined routes, if they exist
if (length(self$server$get_data("user-routes")) > 0) {

plugin <- list(
on_attach = function(server) {
user_routes <- server$get_data("user-routes")
Expand All@@ -1243,26 +1243,26 @@ Dash <- R6::R6Class(
# have all the relevant routes in place anyhow
if (server$plugins$request_routr$has_route("user-routes"))
server$plugins$request_routr$remove_route("user-routes")

router <- server$plugins$request_routr

route <- routr::Route$new()

for (routing in user_routes) {
route$add_handler(method=routing$methods,
path=routing$path,
handler=routing$handler)
}

router$add_route(route, "user-routes")
},
name = "user_routes",
require = "request_routr"
)

self$server$attach(plugin, force = TRUE)
}

if(getAppPath() != FALSE) {
source_dir <- dirname(getAppPath())
private$app_root_modtime <- modtimeFromPath(source_dir, recursive = TRUE, asset_path = private$assets_folder)
Expand DownExpand Up@@ -1304,7 +1304,7 @@ Dash <- R6::R6Class(
timing_information <- self$server$get_data('timing-information')
dash_total <- timing_information[['__dash_server']]
timing_information[['__dash_server']][['dur']] <- round((as.numeric(Sys.time()) - dash_total[['dur']]) * 1000)

header_as_string <- list()

for (item in seq_along(timing_information)) {
Expand All@@ -1317,11 +1317,11 @@ Dash <- R6::R6Class(
if (!is.null(timing_information[[item]]$dur)) {
header_content <- paste0(header_content, ';dur=', timing_information[[item]]$dur)
}

header_as_string[[item]] <- header_content
}

request$response$append_header('Server-Timing',
request$response$append_header('Server-Timing',
paste0(unlist(header_as_string), collapse=", "))
})
}
Expand DownExpand Up@@ -1443,7 +1443,7 @@ Dash <- R6::R6Class(
# flush the context to prepare for the next request cycle
self$server$set_data("timing-information", list())
})
}
}

self$server$ignite(block = block, showcase = showcase, ...)
}
Expand DownExpand Up@@ -1501,10 +1501,10 @@ Dash <- R6::R6Class(
layout_ids = NULL,
layout_render = function() {
layout_ <- if (is.function(private$layout_)) private$layout_() else private$layout_

# ensure that the layout is a component, or a collection of components
layout_ <- private$componentify(layout_)

# store the layout as a (flattened) vector form since we query the
# vector names several times to verify ID naming (among other things)
layout_flat <- rapply(layout_, I)
Expand All@@ -1518,7 +1518,7 @@ Dash <- R6::R6Class(

if (duped) {
duped_ids <- paste(layout_ids[duplicated(layout_ids)], collapse = ", ")

stop(
sprintf("layout ids must be unique -- please check the following list of duplicated ids: '%s'", duped_ids),
call. = FALSE
Expand DownExpand Up@@ -1942,21 +1942,21 @@ Dash <- R6::R6Class(

# 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
}
Expand Down
, '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('^' + ".*" + ' Revert "use correct non-vectorized version of logical and" by alexcjohnson · Pull Request #255 · plotly/dashR · GitHub
Skip to content
Merged
Changes from all commits
Commits
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
116 changes: 58 additions & 58 deletions R/dash.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,7 +50,7 @@ Dash <- R6::R6Class(
#' as `integrity` and `crossorigin`.
#' @param external_stylesheets List. An optional list of valid URLs from which
#' to serve CSS for rendered pages. Each entry can be a string (the URL) or a list
#' with `href` (the URL) and optionally other `<link>` tag attributes such as
#' with `href` (the URL) and optionally other `<link>` tag attributes such as
#' `rel`, `integrity` and `crossorigin`.
#' @param compress Logical. Whether to try to compress files and data served by Fiery.
#' By default, `brotli` is attempted first, then `gzip`, then the `deflate` algorithm,
Expand DownExpand Up@@ -116,9 +116,9 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------
router <- routr::RouteStack$new()
server$set_data("user-routes", list()) # placeholder for custom routes

# ensure that assets_folder is neither NULL nor character(0)
if (!(is.null(private$assets_folder)) && length(private$assets_folder) != 0) {
if (!(is.null(private$assets_folder)) & length(private$assets_folder) != 0) {
if (!(dir.exists(private$assets_folder)) && gsub("/+", "", assets_folder) != "assets") {
warning(sprintf(
"The supplied assets folder, '%s', could not be found in the project directory.",
Expand DownExpand Up@@ -618,9 +618,9 @@ Dash <- R6::R6Class(
#' library(dash)
#' app <- Dash$new()
#'
#' # A handler to redirect requests with `307` status code (temporary redirects);
#' # A handler to redirect requests with `307` status code (temporary redirects);
#' # for permanent redirects (`301`), see the `redirect` method described below
#' #
#' #
#' # A simple single path-to-path redirect
#' app$server_route('/getting-started', function(request, response, keys, ...) {
#' response$status <- 307L
Expand DownExpand Up@@ -653,11 +653,11 @@ Dash <- R6::R6Class(
"methods" = methods)

self$server$set_data("user-routes", user_routes)
},
},

#' @description
#' Redirect a Dash application URL path
#' @details
#' @details
#' This is a convenience method to simplify adding redirects
#' for your Dash application which automatically return a `301`
#' HTTP status code and direct the client to load an alternate URL.
Expand DownExpand Up@@ -705,7 +705,7 @@ Dash <- R6::R6Class(
TRUE
}
}

self$server_route(old_path, handler)
},

Expand All@@ -714,13 +714,13 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------------------
#' @description
#' Retrieves the Dash application layout.
#' @details
#' @details
#' If render is `TRUE`, and the layout is a function,
#' the result of the function (rather than the function itself) is returned.
#' @param render Logical. If the layout is a function, should the function be
#' executed to return the layout? If `FALSE`, the function is returned as-is.
#' @return List or function, depending on the value of `render` (see above).
#' When returning an object of class `dash_component`, the default `print`
#' @return List or function, depending on the value of `render` (see above).
#' When returning an object of class `dash_component`, the default `print`
#' method for this class will display the corresponding pretty-printed JSON
#' representation of the object to the console.
layout_get = function(render = TRUE) {
Expand All@@ -739,7 +739,7 @@ Dash <- R6::R6Class(
#' class.
#' @param value An object of the `dash_component` class, which provides
#' a component or collection of components, specified either as a Dash
#' component or a function that returns a Dash component.
#' component or a function that returns a Dash component.
layout = function(value) {
# private$layout_ <- if (is.function(..1)) ..1 else list(...)
private$layout_ <- value
Expand DownExpand Up@@ -769,9 +769,9 @@ Dash <- R6::R6Class(
#' @description
#' Define a Dash callback.
#' @details
#' Describes a server or clientside callback relating the values of one or more
#' Describes a server or clientside callback relating the values of one or more
#' `output` items to one or more `input` items which will trigger the callback
#' when they change, and optionally `state` items which provide additional
#' when they change, and optionally `state` items which provide additional
#' information but do not trigger the callback directly.
#'
#' For detailed examples of how to use pattern-matching callbacks, see the
Expand All@@ -784,13 +784,13 @@ Dash <- R6::R6Class(
#' object(s) (which should reference layout components), which become
#' argument values for R callback handlers defined in `func`.
#'
#' Here `func` may either be an anonymous R function, a JavaScript function
#' Here `func` may either be an anonymous R function, a JavaScript function
#' provided as a character string, or a call to `clientsideFunction()`, which
#' describes a locally served JavaScript function instead. The latter
#' two methods define a "clientside callback", which updates components
#' without passing data to and from the Dash backend. The latter may offer
#' improved performance relative to callbacks written purely in R.
#' @param output Named list. The `output` argument provides the component `id`
#' @param output Named list. The `output` argument provides the component `id`
#' and `property` which will be updated by the callback; a callback can
#' target one or more outputs (i.e. multiple outputs).
#' @param params Unnamed list; provides [input] and [state] statements, each
Expand DownExpand Up@@ -852,12 +852,12 @@ Dash <- R6::R6Class(
#' the firing of a given callback, and allows introspection of the input/state
#' values given their names. It is only available from within a callback;
#' attempting to use this method outside of a callback will result in a warning.
#'
#'
#' The `callback_context` method returns a list containing three elements:
#' `states`, `triggered`, `inputs`. The first and last of these correspond to
#' the values of `states` and `inputs` for the current invocation of the
#' callback, and `triggered` provides a list of changed properties.
#'
#'
#' @return List comprising elements `states`, `triggered`, `inputs`.
callback_context = function() {
if (is.null(private$callback_context_)) {
Expand All@@ -877,14 +877,14 @@ Dash <- R6::R6Class(
#' duration required to execute a given callback. It may only be called
#' from within a callback; a warning will be thrown and the method will
#' otherwise return `NULL` if invoked outside of a callback.
#'
#'
#' @param name Character. The name of the resource.
#' @param duration Numeric. The time in seconds to report. Internally, this is
#' rounded to the nearest millisecond.
#' @param description Character. A description of the resource.
#'
callback_context.record_timing = function(name,
duration=NULL,
duration=NULL,
description=NULL) {
if (is.null(private$callback_context_)) {
warning("callback_context is undefined; callback_context.record_timing may only be accessed within a callback.")
Expand All@@ -897,7 +897,7 @@ Dash <- R6::R6Class(
stop(paste0("Duplicate resource name ", name, " found."), call.=FALSE)
}

timing_information[[name]] <- list("dur" = round(duration * 1000),
timing_information[[name]] <- list("dur" = round(duration * 1000),
"desc" = description)

self$server$set_data("timing-information", timing_information)
Expand All@@ -906,9 +906,9 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------------------
# return asset URLs
# ------------------------------------------------------------------------
#' @description
#' @description
#' Return a URL for a Dash asset.
#' @details
#' @details
#' The `get_asset_url` method permits retrieval of an asset's URL given its filename.
#' For example, `app$get_asset_url('style.css')` should return `/assets/style.css` when
#' `assets_folder = 'assets'`. By default, the prefix is the value of `requests_pathname_prefix`,
Expand DownExpand Up@@ -973,7 +973,7 @@ Dash <- R6::R6Class(
#' in components such as `dccLink` or `dccLocation`. For example, `app$get_relative_url("/page/")`
#' would return `/app/page/` for an app running on a deployment server. The path must be prefixed with
#' a `/`.
#' @param path Character. A path string prefixed with a leading `/` which directs
#' @param path Character. A path string prefixed with a leading `/` which directs
#' at a path or asset directory.
#' @param requests_pathname_prefix Character. The pathname prefix for the application when
#' deployed. Defaults to the environment variable set by the server,
Expand All@@ -984,12 +984,12 @@ Dash <- R6::R6Class(
asset = get_relative_path(requests_pathname = requests_pathname_prefix, path = path)
return(asset)
},


# ------------------------------------------------------------------------
# return relative asset URLs
# ------------------------------------------------------------------------

#' @description
#' Return a Dash asset path without its prefix.
#' @details
Expand All@@ -998,7 +998,7 @@ Dash <- R6::R6Class(
#' method, by taking a `relative path` as an input, and returning the `path` stripped of the `requests_pathname_prefix`,
#' and any leading or trailing `/`. For example, a path string `/app/homepage/`, would be returned as
#' `homepage`. This is particularly useful for `dccLocation` URL routing.
#' @param path Character. A path string prefixed with a leading `/` which directs
#' @param path Character. A path string prefixed with a leading `/` which directs
#' at a path or asset directory.
#' @param requests_pathname_prefix Character. The pathname prefix for the app on
#' a deployed application. Defaults to the environment variable set by the server,
Expand All@@ -1014,7 +1014,7 @@ Dash <- R6::R6Class(
#' Specify a custom index string for a Dash application.
#' @details
#' The `index_string` method allows the specification of a custom index by changing
#' the default `HTML` template that is generated by the Dash UI. #' Meta tags, CSS, and JavaScript are some examples of features
#' the default `HTML` template that is generated by the Dash UI. #' Meta tags, CSS, and 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
Expand DownExpand Up@@ -1054,11 +1054,11 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(string))
private$custom_index <- validate_keys(string, is_template=TRUE)
},

# ------------------------------------------------------------------------
# modify the templated variables by using the `interpolate_index` method.
# modify the templated variables by using the `interpolate_index` method.
# ------------------------------------------------------------------------
#' @description
#' @description
#' Modify index template variables for a Dash application.
#' @details
#' With the `interpolate_index` method, one can pass a custom index with template string
Expand DownExpand Up@@ -1087,14 +1087,14 @@ Dash <- R6::R6Class(
#' </footer>
#' </body>
#' </html>"
#'
#'

#' # this is the default configuration, but custom configurations
#' # are possible -- the structure of the "config" argument is
#' # a list, in which each element is a JSON key/value pair, when
#' # reformatted as JSON from the list:
#' # e.g. {"routes_pathname_prefix":"/", "ui":false}
#' config <- sprintf("<script id='_dash-config' type='application/json'> %s </script>",
#' config <- sprintf("<script id='_dash-config' type='application/json'> %s </script>",
#' jsonlite::toJSON(app$config, auto_unbox=TRUE))
#'
#' app$interpolate_index(
Expand All@@ -1107,17 +1107,17 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(template_index))
template <- template_index
kwargs <- list(...)

for (name in names(kwargs)) {
key = paste0('\\{\\%', name, '\\%\\}')
template = sub(key, kwargs[[name]], template)
}

}
invisible(validate_keys(names(kwargs), is_template=FALSE))

private$template_index <- template
},

# ------------------------------------------------------------------------
# specify a custom title
# ------------------------------------------------------------------------
Expand All@@ -1130,7 +1130,7 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(string))
private$name <- string
},

# ------------------------------------------------------------------------
# convenient fiery wrappers
# ------------------------------------------------------------------------
Expand All@@ -1155,7 +1155,7 @@ Dash <- R6::R6Class(
#' @param dev_tools_prune_errors Logical. Reduce tracebacks such that only lines relevant to user code remain, stripping out Fiery and Dash references? Only available with debugging. `TRUE` by default, set to `FALSE` to see the complete traceback. Environment variable: `DASH_PRUNE_ERRORS`.
#' @param dev_tools_silence_routes_logging Logical. Replace Fiery's default logger with `dashLogger` instead (will remove all routes logging)? Enabled with debugging by default because hot reload hash checks generate a lot of requests.
#' @param ... Additional arguments to pass to the `start` handler; see the [fiery] documentation for relevant examples.
#' @examples
#' @examples
#' if (interactive() && require(dash)) {
#' library(dashCoreComponents)
#' library(dashHtmlComponents)
Expand DownExpand Up@@ -1232,7 +1232,7 @@ Dash <- R6::R6Class(

# attach user-defined routes, if they exist
if (length(self$server$get_data("user-routes")) > 0) {

plugin <- list(
on_attach = function(server) {
user_routes <- server$get_data("user-routes")
Expand All@@ -1243,26 +1243,26 @@ Dash <- R6::R6Class(
# have all the relevant routes in place anyhow
if (server$plugins$request_routr$has_route("user-routes"))
server$plugins$request_routr$remove_route("user-routes")

router <- server$plugins$request_routr

route <- routr::Route$new()

for (routing in user_routes) {
route$add_handler(method=routing$methods,
path=routing$path,
handler=routing$handler)
}

router$add_route(route, "user-routes")
},
name = "user_routes",
require = "request_routr"
)

self$server$attach(plugin, force = TRUE)
}

if(getAppPath() != FALSE) {
source_dir <- dirname(getAppPath())
private$app_root_modtime <- modtimeFromPath(source_dir, recursive = TRUE, asset_path = private$assets_folder)
Expand DownExpand Up@@ -1304,7 +1304,7 @@ Dash <- R6::R6Class(
timing_information <- self$server$get_data('timing-information')
dash_total <- timing_information[['__dash_server']]
timing_information[['__dash_server']][['dur']] <- round((as.numeric(Sys.time()) - dash_total[['dur']]) * 1000)

header_as_string <- list()

for (item in seq_along(timing_information)) {
Expand All@@ -1317,11 +1317,11 @@ Dash <- R6::R6Class(
if (!is.null(timing_information[[item]]$dur)) {
header_content <- paste0(header_content, ';dur=', timing_information[[item]]$dur)
}

header_as_string[[item]] <- header_content
}

request$response$append_header('Server-Timing',
request$response$append_header('Server-Timing',
paste0(unlist(header_as_string), collapse=", "))
})
}
Expand DownExpand Up@@ -1443,7 +1443,7 @@ Dash <- R6::R6Class(
# flush the context to prepare for the next request cycle
self$server$set_data("timing-information", list())
})
}
}

self$server$ignite(block = block, showcase = showcase, ...)
}
Expand DownExpand Up@@ -1501,10 +1501,10 @@ Dash <- R6::R6Class(
layout_ids = NULL,
layout_render = function() {
layout_ <- if (is.function(private$layout_)) private$layout_() else private$layout_

# ensure that the layout is a component, or a collection of components
layout_ <- private$componentify(layout_)

# store the layout as a (flattened) vector form since we query the
# vector names several times to verify ID naming (among other things)
layout_flat <- rapply(layout_, I)
Expand All@@ -1518,7 +1518,7 @@ Dash <- R6::R6Class(

if (duped) {
duped_ids <- paste(layout_ids[duplicated(layout_ids)], collapse = ", ")

stop(
sprintf("layout ids must be unique -- please check the following list of duplicated ids: '%s'", duped_ids),
call. = FALSE
Expand DownExpand Up@@ -1942,21 +1942,21 @@ Dash <- R6::R6Class(

# 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
}
Expand Down
, '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); } })(); })(); Revert "use correct non-vectorized version of logical and" by alexcjohnson · Pull Request #255 · plotly/dashR · GitHub
Skip to content
Merged
Changes from all commits
Commits
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
116 changes: 58 additions & 58 deletions R/dash.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,7 +50,7 @@ Dash <- R6::R6Class(
#' as `integrity` and `crossorigin`.
#' @param external_stylesheets List. An optional list of valid URLs from which
#' to serve CSS for rendered pages. Each entry can be a string (the URL) or a list
#' with `href` (the URL) and optionally other `<link>` tag attributes such as
#' with `href` (the URL) and optionally other `<link>` tag attributes such as
#' `rel`, `integrity` and `crossorigin`.
#' @param compress Logical. Whether to try to compress files and data served by Fiery.
#' By default, `brotli` is attempted first, then `gzip`, then the `deflate` algorithm,
Expand DownExpand Up@@ -116,9 +116,9 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------
router <- routr::RouteStack$new()
server$set_data("user-routes", list()) # placeholder for custom routes

# ensure that assets_folder is neither NULL nor character(0)
if (!(is.null(private$assets_folder)) && length(private$assets_folder) != 0) {
if (!(is.null(private$assets_folder)) & length(private$assets_folder) != 0) {
if (!(dir.exists(private$assets_folder)) && gsub("/+", "", assets_folder) != "assets") {
warning(sprintf(
"The supplied assets folder, '%s', could not be found in the project directory.",
Expand DownExpand Up@@ -618,9 +618,9 @@ Dash <- R6::R6Class(
#' library(dash)
#' app <- Dash$new()
#'
#' # A handler to redirect requests with `307` status code (temporary redirects);
#' # A handler to redirect requests with `307` status code (temporary redirects);
#' # for permanent redirects (`301`), see the `redirect` method described below
#' #
#' #
#' # A simple single path-to-path redirect
#' app$server_route('/getting-started', function(request, response, keys, ...) {
#' response$status <- 307L
Expand DownExpand Up@@ -653,11 +653,11 @@ Dash <- R6::R6Class(
"methods" = methods)

self$server$set_data("user-routes", user_routes)
},
},

#' @description
#' Redirect a Dash application URL path
#' @details
#' @details
#' This is a convenience method to simplify adding redirects
#' for your Dash application which automatically return a `301`
#' HTTP status code and direct the client to load an alternate URL.
Expand DownExpand Up@@ -705,7 +705,7 @@ Dash <- R6::R6Class(
TRUE
}
}

self$server_route(old_path, handler)
},

Expand All@@ -714,13 +714,13 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------------------
#' @description
#' Retrieves the Dash application layout.
#' @details
#' @details
#' If render is `TRUE`, and the layout is a function,
#' the result of the function (rather than the function itself) is returned.
#' @param render Logical. If the layout is a function, should the function be
#' executed to return the layout? If `FALSE`, the function is returned as-is.
#' @return List or function, depending on the value of `render` (see above).
#' When returning an object of class `dash_component`, the default `print`
#' @return List or function, depending on the value of `render` (see above).
#' When returning an object of class `dash_component`, the default `print`
#' method for this class will display the corresponding pretty-printed JSON
#' representation of the object to the console.
layout_get = function(render = TRUE) {
Expand All@@ -739,7 +739,7 @@ Dash <- R6::R6Class(
#' class.
#' @param value An object of the `dash_component` class, which provides
#' a component or collection of components, specified either as a Dash
#' component or a function that returns a Dash component.
#' component or a function that returns a Dash component.
layout = function(value) {
# private$layout_ <- if (is.function(..1)) ..1 else list(...)
private$layout_ <- value
Expand DownExpand Up@@ -769,9 +769,9 @@ Dash <- R6::R6Class(
#' @description
#' Define a Dash callback.
#' @details
#' Describes a server or clientside callback relating the values of one or more
#' Describes a server or clientside callback relating the values of one or more
#' `output` items to one or more `input` items which will trigger the callback
#' when they change, and optionally `state` items which provide additional
#' when they change, and optionally `state` items which provide additional
#' information but do not trigger the callback directly.
#'
#' For detailed examples of how to use pattern-matching callbacks, see the
Expand All@@ -784,13 +784,13 @@ Dash <- R6::R6Class(
#' object(s) (which should reference layout components), which become
#' argument values for R callback handlers defined in `func`.
#'
#' Here `func` may either be an anonymous R function, a JavaScript function
#' Here `func` may either be an anonymous R function, a JavaScript function
#' provided as a character string, or a call to `clientsideFunction()`, which
#' describes a locally served JavaScript function instead. The latter
#' two methods define a "clientside callback", which updates components
#' without passing data to and from the Dash backend. The latter may offer
#' improved performance relative to callbacks written purely in R.
#' @param output Named list. The `output` argument provides the component `id`
#' @param output Named list. The `output` argument provides the component `id`
#' and `property` which will be updated by the callback; a callback can
#' target one or more outputs (i.e. multiple outputs).
#' @param params Unnamed list; provides [input] and [state] statements, each
Expand DownExpand Up@@ -852,12 +852,12 @@ Dash <- R6::R6Class(
#' the firing of a given callback, and allows introspection of the input/state
#' values given their names. It is only available from within a callback;
#' attempting to use this method outside of a callback will result in a warning.
#'
#'
#' The `callback_context` method returns a list containing three elements:
#' `states`, `triggered`, `inputs`. The first and last of these correspond to
#' the values of `states` and `inputs` for the current invocation of the
#' callback, and `triggered` provides a list of changed properties.
#'
#'
#' @return List comprising elements `states`, `triggered`, `inputs`.
callback_context = function() {
if (is.null(private$callback_context_)) {
Expand All@@ -877,14 +877,14 @@ Dash <- R6::R6Class(
#' duration required to execute a given callback. It may only be called
#' from within a callback; a warning will be thrown and the method will
#' otherwise return `NULL` if invoked outside of a callback.
#'
#'
#' @param name Character. The name of the resource.
#' @param duration Numeric. The time in seconds to report. Internally, this is
#' rounded to the nearest millisecond.
#' @param description Character. A description of the resource.
#'
callback_context.record_timing = function(name,
duration=NULL,
duration=NULL,
description=NULL) {
if (is.null(private$callback_context_)) {
warning("callback_context is undefined; callback_context.record_timing may only be accessed within a callback.")
Expand All@@ -897,7 +897,7 @@ Dash <- R6::R6Class(
stop(paste0("Duplicate resource name ", name, " found."), call.=FALSE)
}

timing_information[[name]] <- list("dur" = round(duration * 1000),
timing_information[[name]] <- list("dur" = round(duration * 1000),
"desc" = description)

self$server$set_data("timing-information", timing_information)
Expand All@@ -906,9 +906,9 @@ Dash <- R6::R6Class(
# ------------------------------------------------------------------------
# return asset URLs
# ------------------------------------------------------------------------
#' @description
#' @description
#' Return a URL for a Dash asset.
#' @details
#' @details
#' The `get_asset_url` method permits retrieval of an asset's URL given its filename.
#' For example, `app$get_asset_url('style.css')` should return `/assets/style.css` when
#' `assets_folder = 'assets'`. By default, the prefix is the value of `requests_pathname_prefix`,
Expand DownExpand Up@@ -973,7 +973,7 @@ Dash <- R6::R6Class(
#' in components such as `dccLink` or `dccLocation`. For example, `app$get_relative_url("/page/")`
#' would return `/app/page/` for an app running on a deployment server. The path must be prefixed with
#' a `/`.
#' @param path Character. A path string prefixed with a leading `/` which directs
#' @param path Character. A path string prefixed with a leading `/` which directs
#' at a path or asset directory.
#' @param requests_pathname_prefix Character. The pathname prefix for the application when
#' deployed. Defaults to the environment variable set by the server,
Expand All@@ -984,12 +984,12 @@ Dash <- R6::R6Class(
asset = get_relative_path(requests_pathname = requests_pathname_prefix, path = path)
return(asset)
},


# ------------------------------------------------------------------------
# return relative asset URLs
# ------------------------------------------------------------------------

#' @description
#' Return a Dash asset path without its prefix.
#' @details
Expand All@@ -998,7 +998,7 @@ Dash <- R6::R6Class(
#' method, by taking a `relative path` as an input, and returning the `path` stripped of the `requests_pathname_prefix`,
#' and any leading or trailing `/`. For example, a path string `/app/homepage/`, would be returned as
#' `homepage`. This is particularly useful for `dccLocation` URL routing.
#' @param path Character. A path string prefixed with a leading `/` which directs
#' @param path Character. A path string prefixed with a leading `/` which directs
#' at a path or asset directory.
#' @param requests_pathname_prefix Character. The pathname prefix for the app on
#' a deployed application. Defaults to the environment variable set by the server,
Expand All@@ -1014,7 +1014,7 @@ Dash <- R6::R6Class(
#' Specify a custom index string for a Dash application.
#' @details
#' The `index_string` method allows the specification of a custom index by changing
#' the default `HTML` template that is generated by the Dash UI. #' Meta tags, CSS, and JavaScript are some examples of features
#' the default `HTML` template that is generated by the Dash UI. #' Meta tags, CSS, and 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
Expand DownExpand Up@@ -1054,11 +1054,11 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(string))
private$custom_index <- validate_keys(string, is_template=TRUE)
},

# ------------------------------------------------------------------------
# modify the templated variables by using the `interpolate_index` method.
# modify the templated variables by using the `interpolate_index` method.
# ------------------------------------------------------------------------
#' @description
#' @description
#' Modify index template variables for a Dash application.
#' @details
#' With the `interpolate_index` method, one can pass a custom index with template string
Expand DownExpand Up@@ -1087,14 +1087,14 @@ Dash <- R6::R6Class(
#' </footer>
#' </body>
#' </html>"
#'
#'

#' # this is the default configuration, but custom configurations
#' # are possible -- the structure of the "config" argument is
#' # a list, in which each element is a JSON key/value pair, when
#' # reformatted as JSON from the list:
#' # e.g. {"routes_pathname_prefix":"/", "ui":false}
#' config <- sprintf("<script id='_dash-config' type='application/json'> %s </script>",
#' config <- sprintf("<script id='_dash-config' type='application/json'> %s </script>",
#' jsonlite::toJSON(app$config, auto_unbox=TRUE))
#'
#' app$interpolate_index(
Expand All@@ -1107,17 +1107,17 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(template_index))
template <- template_index
kwargs <- list(...)

for (name in names(kwargs)) {
key = paste0('\\{\\%', name, '\\%\\}')
template = sub(key, kwargs[[name]], template)
}

}
invisible(validate_keys(names(kwargs), is_template=FALSE))

private$template_index <- template
},

# ------------------------------------------------------------------------
# specify a custom title
# ------------------------------------------------------------------------
Expand All@@ -1130,7 +1130,7 @@ Dash <- R6::R6Class(
assertthat::assert_that(is.character(string))
private$name <- string
},

# ------------------------------------------------------------------------
# convenient fiery wrappers
# ------------------------------------------------------------------------
Expand All@@ -1155,7 +1155,7 @@ Dash <- R6::R6Class(
#' @param dev_tools_prune_errors Logical. Reduce tracebacks such that only lines relevant to user code remain, stripping out Fiery and Dash references? Only available with debugging. `TRUE` by default, set to `FALSE` to see the complete traceback. Environment variable: `DASH_PRUNE_ERRORS`.
#' @param dev_tools_silence_routes_logging Logical. Replace Fiery's default logger with `dashLogger` instead (will remove all routes logging)? Enabled with debugging by default because hot reload hash checks generate a lot of requests.
#' @param ... Additional arguments to pass to the `start` handler; see the [fiery] documentation for relevant examples.
#' @examples
#' @examples
#' if (interactive() && require(dash)) {
#' library(dashCoreComponents)
#' library(dashHtmlComponents)
Expand DownExpand Up@@ -1232,7 +1232,7 @@ Dash <- R6::R6Class(

# attach user-defined routes, if they exist
if (length(self$server$get_data("user-routes")) > 0) {

plugin <- list(
on_attach = function(server) {
user_routes <- server$get_data("user-routes")
Expand All@@ -1243,26 +1243,26 @@ Dash <- R6::R6Class(
# have all the relevant routes in place anyhow
if (server$plugins$request_routr$has_route("user-routes"))
server$plugins$request_routr$remove_route("user-routes")

router <- server$plugins$request_routr

route <- routr::Route$new()

for (routing in user_routes) {
route$add_handler(method=routing$methods,
path=routing$path,
handler=routing$handler)
}

router$add_route(route, "user-routes")
},
name = "user_routes",
require = "request_routr"
)

self$server$attach(plugin, force = TRUE)
}

if(getAppPath() != FALSE) {
source_dir <- dirname(getAppPath())
private$app_root_modtime <- modtimeFromPath(source_dir, recursive = TRUE, asset_path = private$assets_folder)
Expand DownExpand Up@@ -1304,7 +1304,7 @@ Dash <- R6::R6Class(
timing_information <- self$server$get_data('timing-information')
dash_total <- timing_information[['__dash_server']]
timing_information[['__dash_server']][['dur']] <- round((as.numeric(Sys.time()) - dash_total[['dur']]) * 1000)

header_as_string <- list()

for (item in seq_along(timing_information)) {
Expand All@@ -1317,11 +1317,11 @@ Dash <- R6::R6Class(
if (!is.null(timing_information[[item]]$dur)) {
header_content <- paste0(header_content, ';dur=', timing_information[[item]]$dur)
}

header_as_string[[item]] <- header_content
}

request$response$append_header('Server-Timing',
request$response$append_header('Server-Timing',
paste0(unlist(header_as_string), collapse=", "))
})
}
Expand DownExpand Up@@ -1443,7 +1443,7 @@ Dash <- R6::R6Class(
# flush the context to prepare for the next request cycle
self$server$set_data("timing-information", list())
})
}
}

self$server$ignite(block = block, showcase = showcase, ...)
}
Expand DownExpand Up@@ -1501,10 +1501,10 @@ Dash <- R6::R6Class(
layout_ids = NULL,
layout_render = function() {
layout_ <- if (is.function(private$layout_)) private$layout_() else private$layout_

# ensure that the layout is a component, or a collection of components
layout_ <- private$componentify(layout_)

# store the layout as a (flattened) vector form since we query the
# vector names several times to verify ID naming (among other things)
layout_flat <- rapply(layout_, I)
Expand All@@ -1518,7 +1518,7 @@ Dash <- R6::R6Class(

if (duped) {
duped_ids <- paste(layout_ids[duplicated(layout_ids)], collapse = ", ")

stop(
sprintf("layout ids must be unique -- please check the following list of duplicated ids: '%s'", duped_ids),
call. = FALSE
Expand DownExpand Up@@ -1942,21 +1942,21 @@ Dash <- R6::R6Class(

# 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
}
Expand Down