diff --git a/NAMESPACE b/NAMESPACE index 820a327aa..9a559a607 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -204,6 +204,7 @@ export(selectizeInput) export(serverInfo) export(setBookmarkExclude) export(setProgress) +export(setSerializer) export(shinyApp) export(shinyAppDir) export(shinyAppFile) diff --git a/NEWS.md b/NEWS.md index 4a20f505e..f155fcdd6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -31,6 +31,8 @@ shiny 1.0.3.9001 * Added a function `isRunning` to test whether a Shiny app is currently running. ([#1785](https://github.com/rstudio/shiny/pull/1785)) +* Added a function `setSerializer`, which allows authors to specify a function for serializing the value of a custom input. ([#1791](https://github.com/rstudio/shiny/pull/1791)) + ### Bug fixes * Fixed [#1546](https://github.com/rstudio/shiny/issues/1546): make it possible (without any hacks) to write arbitrary data into a module's `session$userData` (which is exactly the same environment as the parent's `session$userData`). To be clear, it allows something like `session$userData$x <- TRUE`, but not something like `session$userData <- TRUE` (that is not allowed in any context, whether you're in the main app, or in a module) ([#1732](https://github.com/rstudio/shiny/pull/1732)). diff --git a/R/serializers.R b/R/serializers.R index 1fdb8b021..35f3b4692 100644 --- a/R/serializers.R +++ b/R/serializers.R @@ -1,3 +1,22 @@ +#' Add a function for serializing an input before bookmarking application state +#' +#' @param inputId Name of the input value. +#' @param fun A function that takes the input value and returns a modified +#' value. The returned value will be used for the test snapshot. +#' @param session A Shiny session object. +#' +#' @keywords internal +#' @export +setSerializer <- function(inputId, fun, session = getDefaultReactiveDomain()) { + if (is.null(session)) { + stop("setSerializer() needs a session object.") + } + + input_impl <- .subset2(session$input, "impl") + input_impl$setMeta(inputId, "shiny.serializer", fun) +} + + # For most types of values, simply return the value unchanged. serializerDefault <- function(value, stateDir) { value @@ -58,12 +77,12 @@ serializeReactiveValues <- function(values, exclude, stateDir = NULL) { # Get the serializer function for this input value. If none specified, use # the default. - serializer <- impl$getMeta(name, "shiny.serializer") - if (is.null(serializer)) - serializer <- serializerDefault + serializer_fun <- impl$getMeta(name, "shiny.serializer") + if (is.null(serializer_fun)) + serializer_fun <- serializerDefault # Apply serializer function. - serializer(val, stateDir) + serializer_fun(val, stateDir) }) # Filter out any values that were marked as unserializable. diff --git a/R/server-input-handlers.R b/R/server-input-handlers.R index cbdb8c475..cc602e5b2 100644 --- a/R/server-input-handlers.R +++ b/R/server-input-handlers.R @@ -148,7 +148,7 @@ registerInputHandler("shiny.number", function(val, ...){ registerInputHandler("shiny.password", function(val, shinysession, name) { # Mark passwords as not serializable - .subset2(shinysession$input, "impl")$setMeta(name, "shiny.serializer", serializerUnserializable) + setSerializer(name, serializerUnserializable) val }) @@ -214,7 +214,7 @@ registerInputHandler("shiny.file", function(val, shinysession, name) { # Need to mark this input value with the correct serializer. When a file is # uploaded the usual way (instead of being restored), this occurs in # session$`@uploadEnd`. - .subset2(shinysession$input, "impl")$setMeta(name, "shiny.serializer", serializerFileInput) + setSerializer(name, serializerFileInput) snapshotPreprocessInput(name, snapshotPreprocessorFileInput) diff --git a/R/shiny.R b/R/shiny.R index 72cca31c8..872cdb2f4 100644 --- a/R/shiny.R +++ b/R/shiny.R @@ -1530,7 +1530,7 @@ ShinySession <- R6Class( fileData <- private$fileUploadContext$getUploadOperation(jobId)$finish() private$.input$set(inputId, fileData) - private$.input$setMeta(inputId, "shiny.serializer", serializerFileInput) + setSerializer(inputId, serializerFileInput) snapshotPreprocessInput(inputId, snapshotPreprocessorFileInput) invisible() diff --git a/inst/staticdocs/index.r b/inst/staticdocs/index.r index 38d8e708b..69f2981b7 100644 --- a/inst/staticdocs/index.r +++ b/inst/staticdocs/index.r @@ -194,6 +194,7 @@ sd_section("Utility functions", "parseQueryString", "plotPNG", "exportTestValues", + "setSerializer", "snapshotExclude", "snapshotPreprocessInput", "snapshotPreprocessOutput", diff --git a/man/setSerializer.Rd b/man/setSerializer.Rd new file mode 100644 index 000000000..ef10eba62 --- /dev/null +++ b/man/setSerializer.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/serializers.R +\name{setSerializer} +\alias{setSerializer} +\title{Add a function for serializing an input before bookmarking application state} +\usage{ +setSerializer(inputId, fun, session = getDefaultReactiveDomain()) +} +\arguments{ +\item{inputId}{Name of the input value.} + +\item{fun}{A function that takes the input value and returns a modified +value. The returned value will be used for the test snapshot.} + +\item{session}{A Shiny session object.} +} +\description{ +Add a function for serializing an input before bookmarking application state +} +\keyword{internal}