Compare commits

..

50 Commits

Author SHA1 Message Date
trestletech
33966cb777 Build out clientData. 2019-10-18 15:03:46 -05:00
trestletech
63ae62ef33 Fleshing out mock session implementation 2019-10-18 14:52:19 -05:00
trestletech
b16e74c203 Add placeholders for all the missing session properties. 2019-10-17 17:03:50 -05:00
trestletech
1616dded0e Test sesssion against all exported render* functions. 2019-10-17 16:36:43 -05:00
trestletech
ced3be337a Pulling out mock session into R6 2019-10-17 12:30:14 -05:00
trestletech
728275af60 Document complex outputs and servers. 2019-10-16 15:47:37 -05:00
trestletech
07592328ce Build testServer. 2019-10-16 14:43:21 -05:00
trestletech
56ec97605e Vignette edits 2019-10-15 17:03:53 -05:00
trestletech
a809bdb447 Enable bulk-running of events via large elapse() values. 2019-10-15 16:45:25 -05:00
trestletech
baf6e57fc4 Set timer to <= instead of <
Makes testing more sensible instead of having to pad by 1 every time.
2019-10-15 16:32:01 -05:00
trestletech
fa7944e096 Mock debounce/throttle. 2019-10-15 16:06:23 -05:00
trestletech
d3a5ac4a9d Merge branch 'jeff/session-timers' into jeff/integration-test 2019-10-15 15:33:20 -05:00
trestletech
e0fd41066a Restore more tests. 2019-10-15 15:25:08 -05:00
trestletech
423f8c2703 Add mock timer to session 2019-10-15 15:15:51 -05:00
trestletech
1adb7528c1 Merge branch 'jeff/session-timers' into jeff/integration-test 2019-10-15 15:03:16 -05:00
trestletech
175843ad37 Merge branch 'jeff/session-timers' into jeff/integration-test 2019-10-15 14:29:32 -05:00
trestletech
fb4cc9d537 Test changes 2019-10-15 10:36:18 -05:00
trestletech
2be8906eeb Make inputs read-only from the tests. 2019-10-15 10:13:41 -05:00
trestletech
6aeda09a58 Enable ggplot2 tests. 2019-10-15 10:05:41 -05:00
trestletech
9e38892c1f Provide default clientdata for plots 2019-10-15 10:03:49 -05:00
trestletech
230488e671 Add HTML and renderUI testing
Inject session and name into render function.
2019-10-15 09:36:54 -05:00
trestletech
b5bdfa1a52 Update vignette to use setInputs 2019-10-15 09:36:29 -05:00
trestletech
1748612e83 Scaffold HTML and image tests. 2019-10-14 12:35:29 -05:00
trestletech
f3d7d7aded Skip known broken tests 2019-10-14 10:11:59 -05:00
trestletech
de9bf891e9 refactor flush 2019-10-14 10:02:17 -05:00
trestletech
517a2face0 WIP migration to setInput
Timer functions still need work.
2019-10-14 09:49:21 -05:00
trestletech
b3bc3a0ad5 Note current limitation 2019-10-10 08:44:57 -05:00
trestletech
15dea2fcbc Add support for comparing the returned value from the module. 2019-10-09 15:59:36 -05:00
trestletech
f25c21eb28 Handle missing outputs 2019-10-09 15:43:31 -05:00
trestletech
640389af05 Test for async errors. 2019-10-09 14:07:58 -05:00
trestletech
593ea60611 Test synchronous errors. 2019-10-09 14:05:32 -05:00
trestletech
03c1932c3a Add support for additional arguments to module 2019-10-09 09:28:24 -05:00
trestletech
e9cf0f8f4f Update namespacing and vignette 2019-10-08 13:58:28 -05:00
trestletech
fd0918c225 Add parallel async test 2019-10-08 10:10:00 -05:00
trestletech
3085a316a7 Initial promises support 2019-10-08 09:59:06 -05:00
trestletech
4acf61d051 WIP Async 2019-10-07 15:11:41 -05:00
trestletech
c6be4aa58a Update test to accommodate new output syntax 2019-10-07 11:27:35 -05:00
trestletech
0205e25a5a Placeholder tests 2019-10-04 15:40:52 -05:00
trestletech
0c6a06da56 Make outputs work on the mock session 2019-10-04 15:37:37 -05:00
trestletech
da6bf7d1de Expand intervals to make tests less fickle 2019-10-04 13:57:03 -05:00
trestletech
3d2c481d27 Test reactivePoll/timer 2019-10-04 13:36:00 -05:00
trestletech
d79c6c701d Test a more complex reactive graph. 2019-10-04 12:37:27 -05:00
trestletech
613615fd69 Better mocking/testing for session end 2019-10-04 12:22:30 -05:00
trestletech
fee07ab97b More session mocking to support getDefaultReactiveDomain usage. 2019-10-04 12:09:57 -05:00
trestletech
79f711794d test with once=TRUE 2019-10-04 10:05:11 -05:00
trestletech
3fd82d08f8 Wire up session handlers 2019-10-04 10:01:34 -05:00
trestletech
267d9e66d8 Unit tests for reactive flushing and timers 2019-10-04 09:17:38 -05:00
trestletech
889b06853c Flush in between each line and use an example that actually requires reactivity 2019-10-03 15:48:56 -05:00
trestletech
43118a11b7 Working on vignette 2019-10-03 14:55:08 -05:00
trestletech
78232d937c First draft of module testing 2019-10-03 14:29:39 -05:00
150 changed files with 1528 additions and 3462 deletions

View File

@@ -5,13 +5,14 @@ matrix:
r: release
r_packages:
- devtools
- roxygen2
script: ./tools/checkDocsCurrent.sh
- name: "Javascript check"
language: node_js
cache: yarn
script: ./tools/checkJSCurrent.sh
node_js:
- "12"
- "10"
- r: 3.2
- r: 3.3
- r: 3.4

View File

@@ -1,7 +1,7 @@
Package: shiny
Type: Package
Title: Web Application Framework for R
Version: 1.4.0.9001
Version: 1.4.0.9000
Authors@R: c(
person("Winston", "Chang", role = c("aut", "cre"), email = "winston@rstudio.com"),
person("Joe", "Cheng", role = "aut", email = "joe@rstudio.com"),
@@ -70,7 +70,7 @@ Imports:
jsonlite (>= 0.9.16),
xtable,
digest,
htmltools (>= 0.4.0.9001),
htmltools (>= 0.4.0),
R6 (>= 2.0),
sourcetools,
later (>= 1.0.0),
@@ -78,8 +78,7 @@ Imports:
tools,
crayon,
rlang (>= 0.4.0),
fastmap (>= 1.0.0),
withr
fastmap (>= 1.0.0)
Suggests:
datasets,
Cairo (>= 1.5-5),
@@ -90,12 +89,7 @@ Suggests:
ggplot2,
reactlog (>= 1.0.0),
magrittr,
shinytest,
yaml,
future,
dygraphs
Remotes:
rstudio/htmltools
yaml
URL: http://shiny.rstudio.com
BugReports: https://github.com/rstudio/shiny/issues
Collate:
@@ -171,8 +165,7 @@ Collate:
'tar.R'
'test-export.R'
'test-module.R'
'test.R'
'update-input.R'
RoxygenNote: 7.0.2
RoxygenNote: 6.1.1
Encoding: UTF-8
Roxygen: list(markdown = TRUE)

View File

@@ -37,7 +37,6 @@ export("conditionStackTrace<-")
export(..stacktraceoff..)
export(..stacktraceon..)
export(HTML)
export(MockShinySession)
export(NS)
export(Progress)
export(a)
@@ -146,7 +145,6 @@ export(maskReactiveContext)
export(memoryCache)
export(modalButton)
export(modalDialog)
export(moduleServer)
export(navbarMenu)
export(navbarPage)
export(navlistPanel)
@@ -217,7 +215,6 @@ export(runExample)
export(runGadget)
export(runGist)
export(runGitHub)
export(runTests)
export(runUrl)
export(safeError)
export(selectInput)
@@ -316,4 +313,3 @@ importFrom(grDevices,dev.cur)
importFrom(grDevices,dev.set)
importFrom(promises,"%...!%")
importFrom(promises,"%...>%")
importFrom(withr,with_options)

16
NEWS.md
View File

@@ -1,4 +1,4 @@
shiny 1.4.0.9001
shiny 1.4.0.9000
===========
## Full changelog
@@ -7,21 +7,11 @@ shiny 1.4.0.9001
### New features
* The new `moduleServer` function provides a simpler interface for creating and using modules. ([#2773](https://github.com/rstudio/shiny/pull/2773))
### Minor new features and improvements
* Fixed [#2042](https://github.com/rstudio/shiny/issues/2042), [#2628](https://github.com/rstudio/shiny/issues/2628): In a `dateInput` and `dateRangeInput`, disabled months and years are now a lighter gray, to make it easier to see that they are disabled. ([#2690](https://github.com/rstudio/shiny/pull/2690))
* `getCurrentOutputInfo()` previously threw an error when called from outside of an output; now it returns `NULL`. ([#2707](https://github.com/rstudio/shiny/pull/2707))
* Added a label to observer that auto-reloads `R/` directory to avoid confusion when using `reactlog`. ([#58](https://github.com/rstudio/reactlog/issues/58))
### Bug fixes
* Fixed [#2606](https://github.com/rstudio/shiny/issues/2606): `debounce()` would not work properly if the code in the reactive expression threw an error on the first run. ([#2652](https://github.com/rstudio/shiny/pull/2652))
* Fixed [#2653](https://github.com/rstudio/shiny/issues/2653): The `dataTableOutput()` could have incorrect output if certain characters were in the column names. ([#2658](https://github.com/rstudio/shiny/pull/2658))
Fixed [#2653](https://github.com/rstudio/shiny/issues/2653): The `dataTableOutput()` could have incorrect output if certain characters were in the column names. ([#2658](https://github.com/rstudio/shiny/pull/2658))
### Documentation Updates
@@ -95,7 +85,7 @@ shiny 1.3.2
### Bug fixes
* Fixed [#2385](https://github.com/rstudio/shiny/issues/2385): Static CSS/JS resources in subapps in R Markdown documents did not render properly. ([#2386](https://github.com/rstudio/shiny/pull/2386))
* Fixed [#2285](https://github.com/rstudio/shiny/issues/2285), [#2288](https://github.com/rstudio/shiny/issues/2288): Static CSS/JS resources in subapps in R Markdown documents did not render properly. ([#2386](https://github.com/rstudio/shiny/pull/2386))
* Fixed [#2280](https://github.com/rstudio/shiny/issues/2280): Shiny applications that used a www/index.html file did not serve up the index file. ([#2382](https://github.com/rstudio/shiny/pull/2382))

36
R/app.R
View File

@@ -13,10 +13,7 @@
#' object to `print()` or [runApp()].
#'
#' @param ui The UI definition of the app (for example, a call to
#' `fluidPage()` with nested controls).
#'
#' If bookmarking is enabled (see `enableBookmarking`), this must be
#' a single argument function that returns the UI definition.
#' `fluidPage()` with nested controls)
#' @param server A function with three parameters: `input`, `output`, and
#' `session`. The function is called once for each session ensuring that each
#' app is independent.
@@ -33,9 +30,11 @@
#' request. Note that the entire request path must match the regular
#' expression in order for the match to be considered successful.
#' @param enableBookmarking Can be one of `"url"`, `"server"`, or
#' `"disable"`. The default value, `NULL`, will respect the setting from
#' any previous calls to [enableBookmarking()]. See [enableBookmarking()]
#' for more information on bookmarking your app.
#' `"disable"`. This is equivalent to calling the
#' [enableBookmarking()] function just before calling
#' `shinyApp()`. With the default value (`NULL`), the app will
#' respect the setting from any previous calls to `enableBookmarking()`.
#' See [enableBookmarking()] for more information.
#' @return An object that represents the app. Printing the object or passing it
#' to [runApp()] will run the app.
#'
@@ -284,8 +283,7 @@ initAutoReloadMonitor <- function(dir) {
".*\\.(r|html?|js|css|png|jpe?g|gif)$")
lastValue <- NULL
observeLabel <- paste0("File Auto-Reload - '", basename(dir), "'")
obs <- observe(label = observeLabel, {
obs <- observe({
files <- sort(list.files(dir, pattern = filePattern, recursive = TRUE,
ignore.case = TRUE))
times <- file.info(files)$mtime
@@ -315,13 +313,14 @@ initAutoReloadMonitor <- function(dir) {
#' adjacent to the `app.R`/`server.R`/`ui.R` files.
#'
#' Since Shiny 1.5.0, this function is called by default when running an
#' application. If it causes problems, there are two ways to opt out. You can
#' either place a file named `_disable_autoload.R` in your R/ directory, or
#' set `options(shiny.autoload.r=FALSE)`. If you set this option, it will
#' application. If it causes problems, you can opt out by using
#' `options(shiny.autoload.r=FALSE)`. Note that in a future version of Shiny,
#' this option will no longer be available. If you set this option, it will
#' affect any application that runs later in the same R session, potentially
#' breaking it, so after running your application, you should unset option with
#' `options(shiny.autoload.r=NULL)`
#'
#'
#' @details The files are sourced in alphabetical order (as determined by
#' [list.files]). `global.R` is evaluated before the supporting R files in the
#' `R/` directory.
@@ -340,21 +339,8 @@ loadSupport <- function(appDir, renv=new.env(parent=globalenv()), globalrenv=glo
}
helpersDir <- file.path(appDir, "R")
disabled <- list.files(helpersDir, pattern="^_disable_autoload\\.r$", recursive=FALSE, ignore.case=TRUE)
if (length(disabled) > 0){
message("R/_disable_autoload.R detected; not loading the R/ directory automatically")
return(invisible(renv))
}
helpers <- list.files(helpersDir, pattern="\\.[rR]$", recursive=FALSE, full.names=TRUE)
if (length(helpers) > 0){
message("Automatically loading ", length(helpers), " .R file",
ifelse(length(helpers) != 1, "s", ""),
" found in the R/ directory.\nSee https://rstd.io/shiny-autoload for more info.")
}
lapply(helpers, sourceUTF8, envir=renv)
invisible(renv)

View File

@@ -231,12 +231,8 @@ column <- function(width, ..., offset = 0) {
stop("column width must be between 1 and 12")
colClass <- paste0("col-sm-", width)
if (offset > 0) {
# offset-md-x is for bootstrap 4 forward compat
# (every size tier has been bumped up one level)
# https://github.com/twbs/bootstrap/blob/74b8fe7/docs/4.3/migration/index.html#L659
colClass <- paste0(colClass, " offset-md-", offset, " col-sm-offset-", offset)
}
if (offset > 0)
colClass <- paste0(colClass, " col-sm-offset-", offset)
div(class = colClass, ...)
}
@@ -570,7 +566,7 @@ splitLayout <- function(..., cellWidths = NULL, cellArgs = list()) {
#' @param flex Determines how space should be distributed to the cells. Can be a
#' single value like `1` or `2` to evenly distribute the available
#' space; or use a vector of numbers to specify the proportions. For example,
#' `flex = c(2, 3)` would cause the space to be split 40%/60% between
#' `flex = c(2, 3)` would cause the space to be split 40\%/60\% between
#' two cells. NA values will cause the corresponding cell to be sized
#' according to its contents (without growing or shrinking).
#' @param width,height The total amount of width and height to use for the

View File

@@ -103,7 +103,7 @@ basicPage <- function(...) {
#' *automatic* height; that is, they determine their own height based on
#' the height of their contained elements. However,
#' `fillPage(plotOutput("plot", height = "100%"))` will work because
#' `fillPage` fixes the `<body>` height at 100% of the window height.
#' `fillPage` fixes the `<body>` height at 100\% of the window height.
#'
#' Note that `fillPage(plotOutput("plot"))` will not cause the plot to fill
#' the page. Like most Shiny output widgets, `plotOutput`'s default height
@@ -793,43 +793,50 @@ buildTabItem <- function(index, tabsetId, foundSelected, tabs = NULL,
#' Create a text output element
#'
#' Render a reactive output variable as text within an application page.
#' `textOutput()` is usually paired with [renderText()] and puts regular text
#' in `<div>` or `<span>`; `verbatimTextOutput()` is usually paired with
#' [renderPrint()] and provudes fixed-width text in a `<pre>`.
#'
#' In both funtions, text is HTML-escaped prior to rendering.
#'
#' Render a reactive output variable as text within an application page. The
#' text will be included within an HTML `div` tag by default.
#' @param outputId output variable to read the value from
#' @param container a function to generate an HTML element to contain the text
#' @param inline use an inline (`span()`) or block container (`div()`)
#' for the output
#' @return A output element for use in UI.
#' @return A text output element that can be included in a panel
#' @details Text is HTML-escaped prior to rendering. This element is often used
#' to display [renderText] output variables.
#' @examples
#' h3(textOutput("caption"))
#' @export
textOutput <- function(outputId, container = if (inline) span else div, inline = FALSE) {
container(id = outputId, class = "shiny-text-output")
}
#' Create a verbatim text output element
#'
#' Render a reactive output variable as verbatim text within an
#' application page. The text will be included within an HTML `pre` tag.
#' @param outputId output variable to read the value from
#' @param placeholder if the output is empty or `NULL`, should an empty
#' rectangle be displayed to serve as a placeholder? (does not affect
#' behavior when the the output in nonempty)
#' @return A verbatim text output element that can be included in a panel
#' @details Text is HTML-escaped prior to rendering. This element is often used
#' with the [renderPrint] function to preserve fixed-width formatting
#' of printed objects.
#' @examples
#' ## Only run this example in interactive R sessions
#' if (interactive()) {
#' shinyApp(
#' ui = basicPage(
#' textInput("txt", "Enter the text to display below:"),
#' textOutput("text"),
#' verbatimTextOutput("verb")
#' verbatimTextOutput("default"),
#' verbatimTextOutput("placeholder", placeholder = TRUE)
#' ),
#' server = function(input, output) {
#' output$text <- renderText({ input$txt })
#' output$verb <- renderText({ input$txt })
#' output$default <- renderText({ input$txt })
#' output$placeholder <- renderText({ input$txt })
#' }
#' )
#' }
#' @export
textOutput <- function(outputId, container = if (inline) span else div, inline = FALSE) {
container(id = outputId, class = "shiny-text-output")
}
#' @param placeholder if the output is empty or `NULL`, should an empty
#' rectangle be displayed to serve as a placeholder? (does not affect
#' behavior when the the output in nonempty)
#' @export
#' @rdname textOutput
verbatimTextOutput <- function(outputId, placeholder = FALSE) {
pre(id = outputId,
class = paste(c("shiny-text-output", if (!placeholder) "noplaceholder"),

View File

@@ -133,7 +133,7 @@ captureStackTraces <- function(expr) {
createStackTracePromiseDomain <- function() {
# These are actually stateless, we wouldn't have to create a new one each time
# if we didn't want to. They're pretty cheap though.
d <- promises::new_promise_domain(
wrapOnFulfilled = function(onFulfilled) {
force(onFulfilled)
@@ -266,10 +266,10 @@ withLogErrors <- function(expr,
printError <- function(cond,
full = getOption("shiny.fullstacktrace", FALSE),
offset = getOption("shiny.stacktraceoffset", TRUE)) {
warning(call. = FALSE, immediate. = TRUE, sprintf("Error in %s: %s",
warning(call. = FALSE, immediate. = TRUE, sprintf("Error in %s: %s",
getCallNames(list(conditionCall(cond))), conditionMessage(cond)))
printStackTrace(cond, full = full, offset = offset)
}
@@ -282,16 +282,16 @@ printStackTrace <- function(cond,
should_drop <- !full
should_strip <- !full
should_prune <- !full
stackTraceCalls <- c(
attr(cond, "deep.stack.trace", exact = TRUE),
list(attr(cond, "stack.trace", exact = TRUE))
)
stackTraceParents <- lapply(stackTraceCalls, attr, which = "parents", exact = TRUE)
stackTraceCallNames <- lapply(stackTraceCalls, getCallNames)
stackTraceCalls <- lapply(stackTraceCalls, offsetSrcrefs, offset = offset)
# Use dropTrivialFrames logic to remove trailing bits (.handleSimpleError, h)
if (should_drop) {
# toKeep is a list of logical vectors, of which elements (stack frames) to keep
@@ -301,7 +301,7 @@ printStackTrace <- function(cond,
stackTraceCallNames <- mapply(stackTraceCallNames, FUN = `[`, toKeep, SIMPLIFY = FALSE)
stackTraceParents <- mapply(stackTraceParents, FUN = `[`, toKeep, SIMPLIFY = FALSE)
}
delayedAssign("all_true", {
# List of logical vectors that are all TRUE, the same shape as
# stackTraceCallNames. Delay the evaluation so we don't create it unless
@@ -310,7 +310,7 @@ printStackTrace <- function(cond,
rep_len(TRUE, length(st))
})
})
# stripStackTraces and lapply(stackTraceParents, pruneStackTrace) return lists
# of logical vectors. Use mapply(FUN = `&`) to boolean-and each pair of the
# logical vectors.
@@ -320,7 +320,7 @@ printStackTrace <- function(cond,
FUN = `&`,
SIMPLIFY = FALSE
)
dfs <- mapply(seq_along(stackTraceCalls), rev(stackTraceCalls), rev(stackTraceCallNames), rev(toShow), FUN = function(i, calls, nms, index) {
st <- data.frame(
num = rev(which(index)),
@@ -329,7 +329,7 @@ printStackTrace <- function(cond,
category = rev(getCallCategories(calls[index])),
stringsAsFactors = FALSE
)
if (i != 1) {
message("From earlier call:")
}
@@ -357,7 +357,7 @@ printStackTrace <- function(cond,
st
}, SIMPLIFY = FALSE)
invisible()
}
@@ -372,7 +372,7 @@ printStackTrace <- function(cond,
extractStackTrace <- function(calls,
full = getOption("shiny.fullstacktrace", FALSE),
offset = getOption("shiny.stacktraceoffset", TRUE)) {
shinyDeprecated(NULL,
"extractStackTrace is deprecated. Please contact the Shiny team if you were using this functionality.",
version = "1.0.5")
@@ -459,19 +459,19 @@ stripOneStackTrace <- function(stackTrace, truncateFloor, startingScore) {
prefix <- rep_len(FALSE, indexOfFloor)
}
}
if (length(stackTrace) == 0) {
return(list(score = startingScore, character(0)))
}
score <- rep.int(0L, length(stackTrace))
score[stackTrace == "..stacktraceon.."] <- 1L
score[stackTrace == "..stacktraceoff.."] <- -1L
score <- startingScore + cumsum(score)
toShow <- score > 0 & !(stackTrace %in% c("..stacktraceon..", "..stacktraceoff..", "..stacktracefloor.."))
list(score = utils::tail(score, 1), trace = c(prefix, toShow))
}
@@ -486,11 +486,11 @@ pruneStackTrace <- function(parents) {
# sufficient; we also need to drop nodes that are the last child, but one of
# their ancestors is not.
is_dupe <- duplicated(parents, fromLast = TRUE)
# The index of the most recently seen node that was actually kept instead of
# dropped.
current_node <- 0
# Loop over the parent indices. Anything that is not parented by current_node
# (a.k.a. last-known-good node), or is a dupe, can be discarded. Anything that
# is kept becomes the new current_node.
@@ -502,7 +502,7 @@ pruneStackTrace <- function(parents) {
FALSE
}
}, FUN.VALUE = logical(1))
include
}
@@ -515,7 +515,7 @@ dropTrivialFrames <- function(callnames) {
# What's the last that *didn't* match stop/.handleSimpleError/h?
lastGoodCall <- max(which(!hideable))
toRemove <- length(callnames) - lastGoodCall
c(
rep_len(TRUE, length(callnames) - toRemove),
rep_len(FALSE, toRemove)
@@ -530,10 +530,10 @@ offsetSrcrefs <- function(calls, offset = TRUE) {
# E.g. for "foo [bar.R:10]", line 10 of bar.R will be part of
# the definition of foo().
srcrefs <- c(utils::tail(srcrefs, -1), list(NULL))
calls <- setSrcRefs(calls, srcrefs)
}
calls
}
@@ -550,7 +550,7 @@ formatStackTrace <- function(calls, indent = " ",
shinyDeprecated(NULL,
"extractStackTrace is deprecated. Please contact the Shiny team if you were using this functionality.",
version = "1.0.5")
st <- extractStackTrace(calls, full = full, offset = offset)
if (nrow(st) == 0) {
return(character(0))

View File

@@ -96,9 +96,9 @@ dateRangeInput <- function(inputId, label, start = NULL, end = NULL,
shinyInputLabel(inputId, label),
# input-daterange class is needed for dropdown behavior
div(class = "input-daterange input-group input-group-sm",
div(class = "input-daterange input-group",
tags$input(
class = "form-control",
class = "input-sm form-control",
type = "text",
`data-date-language` = language,
`data-date-week-start` = weekstart,
@@ -109,14 +109,9 @@ dateRangeInput <- function(inputId, label, start = NULL, end = NULL,
`data-initial-date` = start,
`data-date-autoclose` = if (autoclose) "true" else "false"
),
# input-group-prepend and input-group-append are for bootstrap 4 forward compat
span(class = "input-group-addon input-group-prepend input-group-append",
span(class = "input-group-text",
separator
)
),
span(class = "input-group-addon", separator),
tags$input(
class = "form-control",
class = "input-sm form-control",
type = "text",
`data-date-language` = language,
`data-date-week-start` = weekstart,

View File

@@ -11,15 +11,8 @@
#' @param multiple Whether the user should be allowed to select and upload
#' multiple files at once. **Does not work on older browsers, including
#' Internet Explorer 9 and earlier.**
#' @param accept A character vector of "unique file type specifiers" which
#' gives the browser a hint as to the type of file the server expects.
#' Many browsers use this prevent the user from selecting an invalid file.
#'
#' A unique file type specifier can be:
#' * A case insensitive extension like `.csv` or `.rds`.
#' * A valid MIME type, like `text/plain` or `application/pdf`
#' * One of `audio/*`, `video/*`, or `image/*` meaning any audio, video,
#' or image type, respectively.
#' @param accept A character vector of MIME types; gives the browser a hint of
#' what kind of files the server is expecting.
#' @param buttonLabel The label used on the button. Can be text or an HTML tag
#' object.
#' @param placeholder The text to show before a file has been uploaded.
@@ -31,7 +24,13 @@
#' ui <- fluidPage(
#' sidebarLayout(
#' sidebarPanel(
#' fileInput("file1", "Choose CSV File", accept = ".csv"),
#' fileInput("file1", "Choose CSV File",
#' accept = c(
#' "text/csv",
#' "text/comma-separated-values,text/plain",
#' ".csv")
#' ),
#' tags$hr(),
#' checkboxInput("header", "Header", TRUE)
#' ),
#' mainPanel(
@@ -42,13 +41,17 @@
#'
#' server <- function(input, output) {
#' output$contents <- renderTable({
#' file <- input$file1
#' ext <- tools::file_ext(file$datapath)
#' # input$file1 will be NULL initially. After the user selects
#' # and uploads a file, it will be a data frame with 'name',
#' # 'size', 'type', and 'datapath' columns. The 'datapath'
#' # column will contain the local filenames where the data can
#' # be found.
#' inFile <- input$file1
#'
#' req(file)
#' validate(need(ext == "csv", "Please upload a csv file"))
#' if (is.null(inFile))
#' return(NULL)
#'
#' read.csv(file$datapath, header = input$header)
#' read.csv(inFile$datapath, header = input$header)
#' })
#' }
#'
@@ -106,8 +109,7 @@ fileInput <- function(inputId, label, multiple = FALSE, accept = NULL,
shinyInputLabel(inputId, label),
div(class = "input-group",
# input-group-prepend is for bootstrap 4 compat
tags$label(class = "input-group-btn input-group-prepend",
tags$label(class = "input-group-btn",
span(class = "btn btn-default btn-file",
buttonLabel,
inputTag
@@ -120,7 +122,7 @@ fileInput <- function(inputId, label, multiple = FALSE, accept = NULL,
tags$div(
id=paste(inputId, "_progress", sep=""),
class="progress active shiny-file-input-progress",
class="progress progress-striped active shiny-file-input-progress",
tags$div(class="progress-bar")
)
)

View File

@@ -1,54 +1,55 @@
#' Insert and remove UI objects
#' Insert UI objects
#'
#' These functions allow you to dynamically add and remove arbirary UI
#' into your app, whenever you want, as many times as you want.
#' Unlike [renderUI()], the UI generated with `insertUI()` is persistent:
#' once it's created, it stays there until removed by `removeUI()`. Each
#' new call to `insertUI()` creates more UI objects, in addition to
#' Insert a UI object into the app.
#'
#' This function allows you to dynamically add an arbitrarily large UI
#' object into your app, whenever you want, as many times as you want.
#' Unlike [renderUI()], the UI generated with `insertUI`
#' is not updatable as a whole: once it's created, it stays there. Each
#' new call to `insertUI` creates more UI objects, in addition to
#' the ones already there (all independent from one another). To
#' update a part of the UI (ex: an input object), you must use the
#' appropriate `render` function or a customized `reactive`
#' function.
#' function. To remove any part of your UI, use [removeUI()].
#'
#' It's particularly useful to pair `removeUI` with `insertUI()`, but there is
#' no restriction on what you can use on. Any element that can be selected
#' through a jQuery selector can be removed through this function.
#' @param selector A string that is accepted by jQuery's selector (i.e. the
#' string `s` to be placed in a `$(s)` jQuery call). This selector
#' will determine the element(s) relative to which you want to insert your
#' UI object.
#'
#' @param selector A string that is accepted by jQuery's selector
#' (i.e. the string `s` to be placed in a `$(s)` jQuery call).
#'
#' For `insertUI()` this determines the element(s) relative to which you
#' want to insert your UI object. For `removeUI()` this determine the
#' element(s) to be removed. If you want to remove a Shiny input or output,
#' note that many of these are wrapped in `<div>`s, so you may need to use a
#' somewhat complex selector --- see the Examples below. (Alternatively, you
#' could also wrap the inputs/outputs that you want to be able to remove
#' easily in a `<div>` with an id.)
#' @param where Where your UI object should go relative to the selector:
#' \describe{
#' \item{`beforeBegin`}{Before the selector element itself}
#' \item{`afterBegin`}{Just inside the selector element, before its
#' first child}
#' \item{`beforeEnd`}{Just inside the selector element, after its
#' last child (default)}
#' \item{`afterEnd`}{After the selector element itself}
#' }
#' Adapted from <https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML>.
#' \describe{
#' \item{`beforeBegin`}{Before the selector element itself}
#' \item{`afterBegin`}{Just inside the selector element, before its
#' first child}
#' \item{`beforeEnd`}{Just inside the selector element, after its
#' last child (default)}
#' \item{`afterEnd`}{After the selector element itself}
#' }
#' Adapted from
#' [here](https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML).
#'
#' @param ui The UI object you want to insert. This can be anything that
#' you usually put inside your apps's `ui` function. If you're inserting
#' multiple elements in one call, make sure to wrap them in either a
#' `tagList()` or a `tags$div()` (the latter option has the
#' advantage that you can give it an `id` to make it easier to
#' reference or remove it later on). If you want to insert raw html, use
#' `ui = HTML()`.
#' you usually put inside your apps's `ui` function. If you're inserting
#' multiple elements in one call, make sure to wrap them in either a
#' `tagList()` or a `tags$div()` (the latter option has the
#' advantage that you can give it an `id` to make it easier to
#' reference or remove it later on). If you want to insert raw html, use
#' `ui = HTML()`.
#'
#' @param multiple In case your selector matches more than one element,
#' `multiple` determines whether Shiny should insert the UI object
#' relative to all matched elements or just relative to the first
#' matched element (default).
#' @param immediate Whether the UI object should be immediately inserted
#' or removed, or whether Shiny should wait until all outputs have been
#' updated and all observers have been run (default).
#' @param session The shiny session. Advanced use only.
#' `multiple` determines whether Shiny should insert the UI object
#' relative to all matched elements or just relative to the first
#' matched element (default).
#'
#' @param immediate Whether the UI object should be immediately inserted into
#' the app when you call `insertUI`, or whether Shiny should wait until
#' all outputs have been updated and all observers have been run (default).
#'
#' @param session The shiny session within which to call `insertUI`.
#'
#' @seealso [removeUI()]
#'
#' @examples
#' ## Only run this example in interactive R sessions
#' if (interactive()) {
@@ -72,26 +73,6 @@
#' # Complete app with UI and server components
#' shinyApp(ui, server)
#' }
#'
#' if (interactive()) {
#' # Define UI
#' ui <- fluidPage(
#' actionButton("rmv", "Remove UI"),
#' textInput("txt", "This is no longer useful")
#' )
#'
#' # Server logic
#' server <- function(input, output, session) {
#' observeEvent(input$rmv, {
#' removeUI(
#' selector = "div:has(> #txt)"
#' )
#' })
#' }
#'
#' # Complete app with UI and server components
#' shinyApp(ui, server)
#' }
#' @export
insertUI <- function(selector,
where = c("beforeBegin", "afterBegin", "beforeEnd", "afterEnd"),
@@ -119,7 +100,60 @@ insertUI <- function(selector,
}
#' @rdname insertUI
#' Remove UI objects
#'
#' Remove a UI object from the app.
#'
#' This function allows you to remove any part of your UI. Once `removeUI`
#' is executed on some element, it is gone forever.
#'
#' While it may be a particularly useful pattern to pair this with
#' [insertUI()] (to remove some UI you had previously inserted),
#' there is no restriction on what you can use `removeUI` on. Any
#' element that can be selected through a jQuery selector can be removed
#' through this function.
#'
#' @param selector A string that is accepted by jQuery's selector (i.e. the
#' string `s` to be placed in a `$(s)` jQuery call). This selector
#' will determine the element(s) to be removed. If you want to remove a
#' Shiny input or output, note that many of these are wrapped in `div`s,
#' so you may need to use a somewhat complex selector --- see the Examples below.
#' (Alternatively, you could also wrap the inputs/outputs that you want to be
#' able to remove easily in a `div` with an id.)
#'
#' @param multiple In case your selector matches more than one element,
#' `multiple` determines whether Shiny should remove all the matched
#' elements or just the first matched element (default).
#'
#' @param immediate Whether the element(s) should be immediately removed from
#' the app when you call `removeUI`, or whether Shiny should wait until
#' all outputs have been updated and all observers have been run (default).
#'
#' @param session The shiny session within which to call `removeUI`.
#'
#' @seealso [insertUI()]
#'
#' @examples
#' ## Only run this example in interactive R sessions
#' if (interactive()) {
#' # Define UI
#' ui <- fluidPage(
#' actionButton("rmv", "Remove UI"),
#' textInput("txt", "This is no longer useful")
#' )
#'
#' # Server logic
#' server <- function(input, output, session) {
#' observeEvent(input$rmv, {
#' removeUI(
#' selector = "div:has(> #txt)"
#' )
#' })
#' }
#'
#' # Complete app with UI and server components
#' shinyApp(ui, server)
#' }
#' @export
removeUI <- function(selector,
multiple = FALSE,

View File

@@ -1,30 +1,3 @@
# Promise helpers taken from:
# https://github.com/rstudio/promises/blob/master/tests/testthat/common.R
# Block until all pending later tasks have executed
wait_for_it <- function() {
while (!later::loop_empty()) {
later::run_now(0.1)
}
}
# Block until the promise is resolved/rejected. If resolved, return the value.
# If rejected, throw (yes throw, not return) the error.
#' @importFrom promises %...!%
#' @importFrom promises %...>%
extract <- function(promise) {
promise_value <- NULL
error <- NULL
promise %...>%
(function(value) promise_value <<- value) %...!%
(function(reason) error <<- reason)
wait_for_it()
if (!is.null(error))
stop(error)
else
promise_value
}
# TODO: is there a way to get this behavior without exporting these functions? R6?
# TODO: clientData is documented as a reactiveValues, which this is not. Is it possible that
# users are currently assigning into clientData? That would not work as expected here.
@@ -69,47 +42,29 @@ extract <- function(promise) {
stop("Single-bracket indexing of mockclientdata is not allowed.")
}
#' Mock Shiny Session
#'
#' @description
#' An R6 class suitable for testing that simulates the `session` parameter
#' provided to Shiny server functions or modules.
#'
#' @include timer.R
#' @export
MockShinySession <- R6Class(
'MockShinySession',
portable = FALSE,
class = FALSE,
public = list(
#' @field env The environment associated with the session.
env = NULL,
#' @field singletons Hardcoded as empty. Needed for rendering HTML (i.e. renderUI)
# Needed for rendering HTML (i.e. renderUI)
singletons = character(0),
#' @field clientData Mock client data that always returns a size for plots
# Define a mock client data that always returns a size for plots
clientData = structure(list(), class="mockclientdata"),
#' @description No-op
#' @param logEntry Not used
reactlog = function(logEntry){},
#' @description No-op
incrementBusyCount = function(){},
#' @field output The shinyoutputs associated with the session
output = NULL,
#' @field input The reactive inputs associated with the session
input = NULL,
#' @field userData An environment initialized as empty.
userData = NULL,
#' @field progressStack A stack of progress objects
progressStack = 'Stack',
#' @description Create a new MockShinySession
initialize = function() {
private$.input <- ReactiveValues$new(dedupe = FALSE, label = "input")
private$flushCBs <- Callbacks$new()
private$flushedCBs <- Callbacks$new()
private$endedCBs <- Callbacks$new()
private$timer <- MockableTimerCallbacks$new()
self$progressStack <- Stack$new()
self$userData <- new.env(parent=emptyenv())
@@ -121,10 +76,7 @@ MockShinySession <- R6Class(
# Create a read-only copy of the inputs reactive.
self$input <- .createReactiveValues(private$.input, readonly = TRUE)
},
#' @description Define a callback to be invoked before a reactive flush
#' @param fun The function to invoke
#' @param once If `TRUE`, will only run once. Otherwise, will run every time reactives are flushed.
onFlush = function(fun, once=TRUE) {
onFlush = function(fun, once) {
if (!isTRUE(once)) {
return(private$flushCBs$register(fun))
} else {
@@ -135,10 +87,7 @@ MockShinySession <- R6Class(
return(dereg)
}
},
#' @description Define a callback to be invoked after a reactive flush
#' @param fun The function to invoke
#' @param once If `TRUE`, will only run once. Otherwise, will run every time reactives are flushed.
onFlushed = function(fun, once=TRUE) {
onFlushed = function(fun, once) {
if (!isTRUE(once)) {
return(private$flushedCBs$register(fun))
} else {
@@ -149,29 +98,18 @@ MockShinySession <- R6Class(
return(dereg)
}
},
#' @description Define a callback to be invoked when the session ends
#' @param sessionEndedCallback The callback to invoke when the session has ended.
onEnded = function(sessionEndedCallback) {
private$endedCBs$register(sessionEndedCallback)
},
#' @description Returns `FALSE` if the session has not yet been closed
isEnded = function(){ private$closed },
#' @description Returns `FALSE` if the session has not yet been closed
isClosed = function(){ private$closed },
#' @description Closes the session
close = function(){ private$closed <- TRUE },
#FIXME: this is wrong. Will need to be more complex.
#' @description Unsophisticated mock implementation that merely invokes
#' the given callback immediately.
#' @param callback The callback ato be invoked.
cycleStartAction = function(callback){ callback() },
#' @description Base64-encode the given file. Needed for image rendering.
#' @param name Not used
#' @param file The file to be encoded
#' @param contentType The content type of the base64-encoded string
# Needed for image rendering. Base64-encode the given file.
fileUrl = function(name, file, contentType='application/octet-stream') {
bytes <- file.info(file)$size
if (is.na(bytes))
@@ -182,24 +120,19 @@ MockShinySession <- R6Class(
return(paste('data:', contentType, ';base64,', b64, sep=''))
},
#' @description Sets reactive values associated with the `session$inputs` object
#' and flushes the reactives.
#' @param ... The inputs to set.
#' @examples
#' s <- MockShinySession$new()
#' s$setInputs(x=1, y=2)
setInputs = function(...) {
vals <- list(...)
mapply(names(vals), vals, FUN = function(name, value) {
private$.input$set(name, value)
# TODO: is there really not a way to access `names` from inside an lapply?
lapply(names(vals), function(k){
v <- vals[[k]]
private$.input$set(k, v)
})
private$flush()
},
#' @description An internal method which shouldn't be used by others.
#' @param millis The number of milliseconds on which to schedule a callback
#' @param callback The function to schedule
.scheduleTask = function(millis, callback) {
scheduleTask = function(millis, callback) {
id <- private$timer$schedule(millis, callback)
# Return a deregistration callback
@@ -207,9 +140,6 @@ MockShinySession <- R6Class(
invisible(private$timer$unschedule(id))
}
},
#' @description Simulate the passing of time by the given number of milliseconds.
#' @param millis The number of milliseconds to advance time.
elapse = function(millis) {
msLeft <- millis
@@ -230,39 +160,22 @@ MockShinySession <- R6Class(
private$timer$elapse(msLeft)
# Run again in case our callbacks resulted in a scheduled
# function that needs executing.
# TODO: needed? We're guaranteed to not have anything to run given the above loop, right?
private$timer$executeElapsed()
private$flush()
},
#' @description An internal method which shouldn't be used by others.
.now = function() {
# Returns elapsed time in milliseconds
private$timer$getElapsed()
now = function() {
# Contract is to return Sys.time, which is seconds, not millis.
private$timer$getElapsed()/1000
},
#' @description An internal method which shouldn't be used by others.
#' @param name The name of the output
#' @param func The render definition
#' @param label Not used
defineOutput = function(name, func, label) {
force(name)
if (!is.null(private$outs[[name]]$obs)) {
private$outs[[name]]$obs$destroy()
}
if (is.null(func)) func <- missingOutput
if (!is.function(func))
stop(paste("Unexpected", class(func), "output for", name))
defineOutput = function(name, value, label) {
obs <- observe({
# We could just stash the promise, but we get an "unhandled promise error". This bypasses
prom <- NULL
tryCatch({
v <- func(self, name)
v <- value(self, name) #TODO: I'm not clear what `name` is supposed to be
if (!promises::is.promise(v)){
# Make our sync value into a promise
prom <- promises::promise(function(resolve, reject){ resolve(v) })
@@ -282,27 +195,14 @@ MockShinySession <- R6Class(
list(val = NULL, err = e)
})
})
private$outs[[name]] <- list(obs = obs, func = func, promise = NULL)
private$outs[[name]] <- list(obs = obs, func = value, promise = NULL)
},
#' @description An internal method which shouldn't be used by others.
#' @param name The name of the output
getOutput = function(name) {
# Unlike the real outputs, we're going to return the last value rather than the unevaluated function
if (is.null(private$outs[[name]])) {
if (is.null(private$outs[[name]]$promise)) {
stop("The test referenced an output that hasn't been defined yet: output$", name)
}
if (is.null(private$outs[[name]]$promise)) {
# Means the output was defined but the observer hasn't had a chance to run
# yet. Run flushReact() now to force the observer to run.
flushReact()
if (is.null(private$outs[[name]]$promise)) {
stop("output$", name, " encountered an unexpected error resolving its promise")
}
}
# Make promise return
v <- extract(private$outs[[name]]$promise)
if (!is.null(v$err)){
@@ -312,83 +212,36 @@ MockShinySession <- R6Class(
}
},
#' @description No-op
#' @param name Not used
#' @param data Not used
#' @param filterFunc Not used
registerDataObj = function(name, data, filterFunc) {},
#' @description No-op
#' @param value Not used
allowReconnect = function(value) {},
#' @description No-op
reload = function() {},
#' @description No-op
#' @param brushId Not used
resetBrush = function(brushId) {
warning("session$brush isn't meaningfully mocked on the MockShinySession")
},
#' @description No-op
#' @param type Not used
#' @param message Not used
sendCustomMessage = function(type, message) {},
#' @description No-op
#' @param type Not used
#' @param message Not used
sendBinaryMessage = function(type, message) {},
#' @description No-op
#' @param inputId Not used
#' @param message Not used
sendInputMessage = function(inputId, message) {},
#' @description No-op
#' @param names Not used
setBookmarkExclude = function(names) {
warning("Bookmarking isn't meaningfully mocked in MockShinySession")
},
#' @description No-op
getBookmarkExclude = function() {
warning("Bookmarking isn't meaningfully mocked in MockShinySession")
},
#' @description No-op
#' @param fun Not used
onBookmark = function(fun) {},
#' @description No-op
#' @param fun Not used
onBookmarked = function(fun) {},
#' @description No-op
onBookmark = function(fun) {
warning("Bookmarking isn't meaningfully mocked in MockShinySession")
},
onBookmarked = function(fun) {
warning("Bookmarking isn't meaningfully mocked in MockShinySession")
},
doBookmark = function() {
warning("Bookmarking isn't meaningfully mocked in MockShinySession")
},
#' @description No-op
#' @param fun Not used
onRestore = function(fun) {},
#' @description No-op
#' @param fun Not used
onRestored = function(fun) {},
#' @description No-op
exportTestValues = function() {},
#' @description No-op
#' @param input Not used
#' @param output Not used
#' @param export Not used
#' @param format Not used
getTestSnapshotUrl = function(input=TRUE, output=TRUE, export=TRUE, format="json") {},
#' @description Returns the given id prefixed by `mock-session-`.
#' @param id The id to modify.
ns = function(id) {
paste0("mock-session-", id) # TODO: does this need to be more complex/intelligent?
},
#' @description Trigger a reactive flush right now.
flushReact = function(){
private$flush()
},
makeScope = function(namespace) {
ns <- NS(namespace)
createSessionProxy(
self,
input = .createReactiveValues(private$.input, readonly = TRUE, ns = ns),
output = structure(.createOutputWriter(self, ns = ns), class = "shinyoutput"),
makeScope = function(namespace) self$makeScope(ns(namespace))
)
}
),
private = list(
@@ -403,14 +256,13 @@ MockShinySession <- R6Class(
flush = function(){
isolate(private$flushCBs$invoke(..stacktraceon = TRUE))
shiny:::flushReact() # namespace to avoid calling our own method
flushReact()
isolate(private$flushedCBs$invoke(..stacktraceon = TRUE))
later::run_now()
}
),
active = list(
# If assigning to `returned`, proactively flush
#' @field returned The value returned from the module
returned = function(value){
if(missing(value)){
return(private$returnedVal)
@@ -421,7 +273,6 @@ MockShinySession <- R6Class(
private$returnedVal <- value
private$flush()
},
#' @field request An empty environment where the request should be. The request isn't meaningfully mocked currently.
request = function(value) {
if (!missing(value)){
stop("session$request can't be assigned to")
@@ -431,4 +282,3 @@ MockShinySession <- R6Class(
}
)
)

View File

@@ -37,100 +37,24 @@ createSessionProxy <- function(parentSession, ...) {
`[[<-.session_proxy` <- `$<-.session_proxy`
#' Shiny modules
#' Invoke a Shiny module
#'
#' Shiny's module feature lets you break complicated UI and server logic into
#' smaller, self-contained pieces. Compared to large monolithic Shiny apps,
#' modules are easier to reuse and easier to reason about. See the article at
#' <http://shiny.rstudio.com/articles/modules.html> to learn more.
#'
#' Starting in Shiny 1.5.0, we recommend using `moduleFunction` instead of
#' `callModule`, because syntax is a little easier to understand.
#'
#' @param module A Shiny module server function.
#' @param module A Shiny module server function
#' @param id An ID string that corresponds with the ID used to call the module's
#' UI function.
#' @param ... For `callModule`, additional parameters to pass to module server
#' function.
#' UI function
#' @param ... Additional parameters to pass to module server function
#' @param session Session from which to make a child scope (the default should
#' almost always be used).
#' almost always be used)
#'
#' @return The return value, if any, from executing the module server function
#' @seealso <http://shiny.rstudio.com/articles/modules.html>
#'
#' @examples
#' # Define the UI for a module
#' counterUI <- function(id, label = "Counter") {
#' ns <- NS(id)
#' tagList(
#' actionButton(ns("button"), label = label),
#' verbatimTextOutput(ns("out"))
#' )
#' }
#'
#' # Define the server logic for a module
#' counterServer <- function(id) {
#' moduleServer(id, function(input, output, session) {
#' count <- reactiveVal(0)
#' observeEvent(input$button, {
#' count(count() + 1)
#' })
#' output$out <- renderText({
#' count()
#' })
#' count
#' })
#' }
#'
#' # Use the module in an app
#' ui <- fluidPage(
#' counterUI("counter1", "Counter #1"),
#' counterUI("counter2", "Counter #2")
#' )
#' server <- function(input, output, session) {
#' counterServer("counter1")
#' counterServer("counter2")
#' }
#' shinyApp(ui, server)
#'
#'
#'
#' # If you want to pass extra parameters to the module's server logic, you can
#' # add them to your function. In this case `prefix` is text that will be
#' # printed before the count.
#' counterServer2 <- function(id, prefix = NULL) {
#' moduleServer(id, function(input, output, session) {
#' count <- reactiveVal(0)
#' observeEvent(input$button, {
#' count(count() + 1)
#' })
#' output$out <- renderText({
#' paste0(prefix, count())
#' })
#' count
#' })
#' }
#'
#' ui <- fluidPage(
#' counterUI("counter", "Counter"),
#' )
#' server <- function(input, output, session) {
#' counterServer2("counter", "The current count is: ")
#' }
#' shinyApp(ui, server)
#'
#' @export
moduleServer <- function(id, module, session = getDefaultReactiveDomain()) {
callModule(module, id, session = session)
}
#' @rdname moduleServer
#' @export
callModule <- function(module, id, ..., session = getDefaultReactiveDomain()) {
if (!inherits(session, "ShinySession") && !inherits(session, "session_proxy")) {
stop("session must be a ShinySession or session_proxy object.")
}
childScope <- session$makeScope(id)
withReactiveDomain(childScope, {

View File

@@ -20,12 +20,50 @@
#' [`shinyOptions(progress.style="old")`][shinyOptions] just once, inside the server
#' function.
#'
#' **Methods**
#' \describe{
#' \item{`initialize(session, min = 0, max = 1)`}{
#' Creates a new progress panel (but does not display it).
#' }
#' \item{`set(value = NULL, message = NULL, detail = NULL)`}{
#' Updates the progress panel. When called the first time, the
#' progress panel is displayed.
#' }
#' \item{`inc(amount = 0.1, message = NULL, detail = NULL)`}{
#' Like `set`, this updates the progress panel. The difference is
#' that `inc` increases the progress bar by `amount`, instead
#' of setting it to a specific value.
#' }
#' \item{`close()`}{
#' Removes the progress panel. Future calls to `set` and
#' `close` will be ignored.
#' }
#' }
#'
#' @param session The Shiny session object, as provided by
#' `shinyServer` to the server function.
#' @param min The value that represents the starting point of the
#' progress bar. Must be less than `max`.
#' @param max The value that represents the end of the progress bar.
#' Must be greater than `min`.
#' @param message A single-element character vector; the message to be
#' displayed to the user, or `NULL` to hide the current message (if any).
#' @param detail A single-element character vector; the detail message to be
#' displayed to the user, or `NULL` to hide the current detail message (if
#' any). The detail message will be shown with a de-emphasized appearance
#' relative to `message`.
#' displayed to the user, or `NULL` to hide the current message
#' (if any).
#' @param detail A single-element character vector; the detail message
#' to be displayed to the user, or `NULL` to hide the current
#' detail message (if any). The detail message will be shown with a
#' de-emphasized appearance relative to `message`.
#' @param value A numeric value at which to set
#' the progress bar, relative to `min` and `max`.
#' @param style Progress display style. If `"notification"` (the default),
#' the progress indicator will show using Shiny's notification API. If
#' `"old"`, use the same HTML and CSS used in Shiny 0.13.2 and below
#' (this is for backward-compatibility).
#' @param amount Single-element numeric vector; the value at which to set
#' the progress bar, relative to `min` and `max`.
#' `NULL` hides the progress bar, if it is currently visible.
#' @param amount For the `inc()` method, a numeric value to increment the
#' progress bar.
#'
#' @examples
#' ## Only run examples in interactive R sessions
@@ -61,17 +99,6 @@ Progress <- R6Class(
'Progress',
public = list(
#' @description Creates a new progress panel (but does not display it).
#' @param session The Shiny session object, as provided by `shinyServer` to
#' the server function.
#' @param min The value that represents the starting point of the progress
#' bar. Must be less than `max`.
#' @param max The value that represents the end of the progress bar. Must be
#' greater than `min`.
#' @param style Progress display style. If `"notification"` (the default),
#' the progress indicator will show using Shiny's notification API. If
#' `"old"`, use the same HTML and CSS used in Shiny 0.13.2 and below (this
#' is for backward-compatibility).
initialize = function(session = getDefaultReactiveDomain(),
min = 0, max = 1,
style = getShinyOption("progress.style", default = "notification"))
@@ -90,11 +117,6 @@ Progress <- R6Class(
session$sendProgress('open', list(id = private$id, style = private$style))
},
#' @description Updates the progress panel. When called the first time, the
#' progress panel is displayed.
#' @param value Single-element numeric vector; the value at which to set the
#' progress bar, relative to `min` and `max`. `NULL` hides the progress
#' bar, if it is currently visible.
set = function(value = NULL, message = NULL, detail = NULL) {
if (private$closed) {
warning("Attempting to set progress, but progress already closed.")
@@ -121,11 +143,6 @@ Progress <- R6Class(
private$session$sendProgress('update', data)
},
#' @description Like `set`, this updates the progress panel. The difference
#' is that `inc` increases the progress bar by `amount`, instead of
#' setting it to a specific value.
#' @param amount For the `inc()` method, a numeric value to increment the
#' progress bar.
inc = function(amount = 0.1, message = NULL, detail = NULL) {
if (is.null(private$value))
private$value <- private$min
@@ -134,17 +151,12 @@ Progress <- R6Class(
self$set(value, message, detail)
},
#' @description Returns the minimum value.
getMin = function() private$min,
#' @description Returns the maximum value.
getMax = function() private$max,
#' @description Returns the current value.
getValue = function() private$value,
#' @description Removes the progress panel. Future calls to `set` and
#' `close` will be ignored.
close = function() {
if (private$closed) {
warning("Attempting to close progress, but progress already closed.")

View File

@@ -2362,24 +2362,20 @@ debounce <- function(r, millis, priority = 100, domain = getDefaultReactiveDomai
when = NULL # the deadline for the timer to fire; NULL if not scheduled
)
# Responsible for tracking when r() changes.
# Responsible for tracking when f() changes.
firstRun <- TRUE
observe({
r()
if (firstRun) {
# During the first run we don't want to set v$when, as this will kick off
# the timer. We only want to do that when we see r() change.
firstRun <<- FALSE
# Ensure r() is called only after setting firstRun to FALSE since r()
# may throw an error
r()
return()
}
# This ensures r() is still tracked after firstRun
r()
# The value (or possibly millis) changed. Start or reset the timer.
v$when <- getDomainTimeMs(domain) + millis()
v$when <- getTime(domain) + millis()/1000
}, label = "debounce tracker", domain = domain, priority = priority)
# This observer is the timer. It rests until v$when elapses, then touches
@@ -2388,13 +2384,13 @@ debounce <- function(r, millis, priority = 100, domain = getDefaultReactiveDomai
if (is.null(v$when))
return()
now <- getDomainTimeMs(domain)
now <- getTime(domain)
if (now >= v$when) {
# Mod by 999999999 to get predictable overflow behavior
v$trigger <- isolate(v$trigger %OR% 0) %% 999999999 + 1
v$when <- NULL
} else {
invalidateLater(v$when - now)
invalidateLater((v$when - now) * 1000)
}
}, label = "debounce timer", domain = domain, priority = priority)
@@ -2439,12 +2435,12 @@ throttle <- function(r, millis, priority = 100, domain = getDefaultReactiveDomai
if (is.null(v$lastTriggeredAt)) {
0
} else {
max(0, v$lastTriggeredAt + millis() - getDomainTimeMs(domain))
max(0, (v$lastTriggeredAt + millis()/1000) - getTime(domain)) * 1000
}
}
trigger <- function() {
v$lastTriggeredAt <- getDomainTimeMs(domain)
v$lastTriggeredAt <- getTime(domain)
# Mod by 999999999 to get predictable overflow behavior
v$trigger <- isolate(v$trigger) %% 999999999 + 1
v$pending <- FALSE

View File

@@ -1230,5 +1230,5 @@ inShinyServer <- function() {
# This check was moved out of the main function body because of an issue with
# the RStudio debugger. (#1474)
isEmptyMessage <- function(msg) {
identical(as.raw(c(0x03, 0xe9)), msg)
identical(charToRaw("\003\xe9"), msg)
}

View File

@@ -35,81 +35,81 @@ getShinyOption <- function(name, default = NULL) {
#' `shinyOptions()`.
#'
#' \describe{
#' \item{shiny.autoreload (defaults to `FALSE`)}{If `TRUE` when a Shiny app is launched, the
#' app directory will be continually monitored for changes to files that
#' have the extensions: r, htm, html, js, css, png, jpg, jpeg, gif. If any
#' changes are detected, all connected Shiny sessions are reloaded. This
#' allows for fast feedback loops when tweaking Shiny UI.
#' \item{shiny.autoreload (defaults to `FALSE`)}{If `TRUE` when a Shiny app is launched, the
#' app directory will be continually monitored for changes to files that
#' have the extensions: r, htm, html, js, css, png, jpg, jpeg, gif. If any
#' changes are detected, all connected Shiny sessions are reloaded. This
#' allows for fast feedback loops when tweaking Shiny UI.
#'
#' Since monitoring for changes is expensive (we simply poll for last
#' modified times), this feature is intended only for development.
#' Since monitoring for changes is expensive (we simply poll for last
#' modified times), this feature is intended only for development.
#'
#' You can customize the file patterns Shiny will monitor by setting the
#' shiny.autoreload.pattern option. For example, to monitor only ui.R:
#' `options(shiny.autoreload.pattern = glob2rx("ui.R"))`
#' You can customize the file patterns Shiny will monitor by setting the
#' shiny.autoreload.pattern option. For example, to monitor only ui.R:
#' `options(shiny.autoreload.pattern = glob2rx("ui.R"))`
#'
#' The default polling interval is 500 milliseconds. You can change this
#' by setting e.g. `options(shiny.autoreload.interval = 2000)` (every
#' two seconds).}
#' \item{shiny.deprecation.messages (defaults to `TRUE`)}{This controls whether messages for
#' deprecated functions in Shiny will be printed. See
#' [shinyDeprecated()] for more information.}
#' \item{shiny.error (defaults to `NULL`)}{This can be a function which is called when an error
#' occurs. For example, `options(shiny.error=recover)` will result a
#' the debugger prompt when an error occurs.}
#' \item{shiny.fullstacktrace (defaults to `FALSE`)}{Controls whether "pretty" (`FALSE`) or full
#' stack traces (`TRUE`) are dumped to the console when errors occur during Shiny app execution.
#' Pretty stack traces attempt to only show user-supplied code, but this pruning can't always
#' be done 100% correctly.}
#' \item{shiny.host (defaults to `"127.0.0.1"`)}{The IP address that Shiny should listen on. See
#' [runApp()] for more information.}
#' \item{shiny.jquery.version (defaults to `3`)}{The major version of jQuery to use.
#' Currently only values of `3` or `1` are supported. If `1`, then jQuery 1.12.4 is used. If `3`,
#' then jQuery 3.4.1 is used.}
#' \item{shiny.json.digits (defaults to `16`)}{The number of digits to use when converting
#' numbers to JSON format to send to the client web browser.}
#' \item{shiny.launch.browser (defaults to `interactive()`)}{A boolean which controls the default behavior
#' when an app is run. See [runApp()] for more information.}
#' \item{shiny.maxRequestSize (defaults to 5MB)}{This is a number which specifies the maximum
#' web request size, which serves as a size limit for file uploads.}
#' \item{shiny.minified (defaults to `TRUE`)}{By default
#' Whether or not to include Shiny's JavaScript as a minified (`shiny.min.js`)
#' or un-minified (`shiny.js`) file. The un-minified version is larger,
#' but can be helpful for development and debugging.}
#' \item{shiny.port (defaults to a random open port)}{A port number that Shiny will listen on. See
#' [runApp()] for more information.}
#' \item{shiny.reactlog (defaults to `FALSE`)}{If `TRUE`, enable logging of reactive events,
#' which can be viewed later with the [reactlogShow()] function.
#' This incurs a substantial performance penalty and should not be used in
#' production.}
#' \item{shiny.sanitize.errors (defaults to `FALSE`)}{If `TRUE`, then normal errors (i.e.
#' errors not wrapped in `safeError`) won't show up in the app; a simple
#' generic error message is printed instead (the error and strack trace printed
#' to the console remain unchanged). If you want to sanitize errors in general, but you DO want a
#' particular error `e` to get displayed to the user, then set this option
#' to `TRUE` and use `stop(safeError(e))` for errors you want the
#' user to see.}
#' \item{shiny.stacktraceoffset (defaults to `TRUE`)}{If `TRUE`, then Shiny's printed stack
#' traces will display srcrefs one line above their usual location. This is
#' an arguably more intuitive arrangement for casual R users, as the name
#' of a function appears next to the srcref where it is defined, rather than
#' where it is currently being called from.}
#' \item{shiny.suppressMissingContextError (defaults to `FALSE`)}{Normally, invoking a reactive
#' outside of a reactive context (or [isolate()]) results in
#' an error. If this is `TRUE`, don't error in these cases. This
#' should only be used for debugging or demonstrations of reactivity at the
#' console.}
#' \item{shiny.testmode (defaults to `FALSE`)}{If `TRUE`, then various features for testing Shiny
#' applications are enabled.}
#' \item{shiny.trace (defaults to `FALSE`)}{Print messages sent between the R server and the web
#' browser client to the R console. This is useful for debugging. Possible
#' values are `"send"` (only print messages sent to the client),
#' `"recv"` (only print messages received by the server), `TRUE`
#' (print all messages), or `FALSE` (default; don't print any of these
#' messages).}
#' \item{shiny.usecairo (defaults to `TRUE`)}{This is used to disable graphical rendering by the
#' Cairo package, if it is installed. See [plotPNG()] for more
#' information.}
#' The default polling interval is 500 milliseconds. You can change this
#' by setting e.g. `options(shiny.autoreload.interval = 2000)` (every
#' two seconds).}
#' \item{shiny.deprecation.messages (defaults to `TRUE`)}{This controls whether messages for
#' deprecated functions in Shiny will be printed. See
#' [shinyDeprecated()] for more information.}
#' \item{shiny.error (defaults to `NULL`)}{This can be a function which is called when an error
#' occurs. For example, `options(shiny.error=recover)` will result a
#' the debugger prompt when an error occurs.}
#' \item{shiny.fullstacktrace (defaults to `FALSE`)}{Controls whether "pretty" (`FALSE`) or full
#' stack traces (`TRUE`) are dumped to the console when errors occur during Shiny app execution.
#' Pretty stack traces attempt to only show user-supplied code, but this pruning can't always
#' be done 100\% correctly.}
#' \item{shiny.host (defaults to `"127.0.0.1"`)}{The IP address that Shiny should listen on. See
#' [runApp()] for more information.}
#' \item{shiny.jquery.version (defaults to `3`)}{The major version of jQuery to use.
#' Currently only values of `3` or `1` are supported. If `1`, then jQuery 1.12.4 is used. If `3`,
#' then jQuery 3.4.1 is used.}
#' \item{shiny.json.digits (defaults to `16`)}{The number of digits to use when converting
#' numbers to JSON format to send to the client web browser.}
#' \item{shiny.launch.browser (defaults to `interactive()`)}{A boolean which controls the default behavior
#' when an app is run. See [runApp()] for more information.}
#' \item{shiny.maxRequestSize (defaults to 5MB)}{This is a number which specifies the maximum
#' web request size, which serves as a size limit for file uploads.}
#' \item{shiny.minified (defaults to `TRUE`)}{By default
#' Whether or not to include Shiny's JavaScript as a minified (`shiny.min.js`)
#' or un-minified (`shiny.js`) file. The un-minified version is larger,
#' but can be helpful for development and debugging.}
#' \item{shiny.port (defaults to a random open port)}{A port number that Shiny will listen on. See
#' [runApp()] for more information.}
#' \item{shiny.reactlog (defaults to `FALSE`)}{If `TRUE`, enable logging of reactive events,
#' which can be viewed later with the [reactlogShow()] function.
#' This incurs a substantial performance penalty and should not be used in
#' production.}
#' \item{shiny.sanitize.errors (defaults to `FALSE`)}{If `TRUE`, then normal errors (i.e.
#' errors not wrapped in `safeError`) won't show up in the app; a simple
#' generic error message is printed instead (the error and strack trace printed
#' to the console remain unchanged). If you want to sanitize errors in general, but you DO want a
#' particular error `e` to get displayed to the user, then set this option
#' to `TRUE` and use `stop(safeError(e))` for errors you want the
#' user to see.}
#' \item{shiny.stacktraceoffset (defaults to `TRUE`)}{If `TRUE`, then Shiny's printed stack
#' traces will display srcrefs one line above their usual location. This is
#' an arguably more intuitive arrangement for casual R users, as the name
#' of a function appears next to the srcref where it is defined, rather than
#' where it is currently being called from.}
#' \item{shiny.suppressMissingContextError (defaults to `FALSE`)}{Normally, invoking a reactive
#' outside of a reactive context (or [isolate()]) results in
#' an error. If this is `TRUE`, don't error in these cases. This
#' should only be used for debugging or demonstrations of reactivity at the
#' console.}
#' \item{shiny.testmode (defaults to `FALSE`)}{If `TRUE`, then various features for testing Shiny
#' applications are enabled.}
#' \item{shiny.trace (defaults to `FALSE`)}{Print messages sent between the R server and the web
#' browser client to the R console. This is useful for debugging. Possible
#' values are `"send"` (only print messages sent to the client),
#' `"recv"` (only print messages received by the server), `TRUE`
#' (print all messages), or `FALSE` (default; don't print any of these
#' messages).}
#' \item{shiny.usecairo (defaults to `TRUE`)}{This is used to disable graphical rendering by the
#' Cairo package, if it is installed. See [plotPNG()] for more
#' information.}
#' }
#' @param ... Options to set, with the form `name = value`.
#' @aliases shiny-options

View File

@@ -723,12 +723,9 @@ ShinySession <- R6Class(
requestFlush = function() {
appsNeedingFlush$set(self$token, self)
},
.scheduleTask = function(millis, callback) {
scheduleTask = function(millis, callback) {
scheduleTask(millis, callback)
},
.now = function(){
getTimeMs()
},
rootScope = function() {
self
},
@@ -1297,9 +1294,6 @@ ShinySession <- R6Class(
getCurrentOutputInfo = function() {
name <- private$currentOutputName
if (is.null(name)) {
return(NULL)
}
tmp_info <- private$outputInfo[[name]] %OR% list(name = name)
@@ -2099,10 +2093,6 @@ outputOptions <- function(x, name, ...) {
#' Get information about the output that is currently being executed.
#'
#' @return A list with information about the current output, including the
#' `name` of the output. If no output is currently being executed, this will
#' return `NULL`.
#'
#' @param session The current Shiny session.
#'
#' @export

View File

@@ -1,79 +1,71 @@
# Promise helpers taken from:
# https://github.com/rstudio/promises/blob/master/tests/testthat/common.R
# Block until all pending later tasks have executed
# FIXME: will this work with multiple promises pending in parallel?
wait_for_it <- function() {
while (!later::loop_empty()) {
later::run_now()
Sys.sleep(0.1)
}
}
# Block until the promise is resolved/rejected. If resolved, return the value.
# If rejected, throw (yes throw, not return) the error.
#' @importFrom promises %...!%
#' @importFrom promises %...>%
extract <- function(promise) {
promise_value <- NULL
error <- NULL
promise %...>%
(function(value) promise_value <<- value) %...!%
(function(reason) error <<- reason)
#' Integration testing for Shiny modules or server functions
#'
#' Offer a way to test the reactive interactions in Shiny --- either in Shiny
#' modules or in the server portion of a Shiny application. For more
#' information, visit [the Shiny Dev Center article on integration
#' testing](https://shiny.rstudio.com/articles/integration-testing.html).
#' @param module The module to test
wait_for_it()
if (!is.null(error))
stop(error)
else
promise_value
}
#' Test a shiny module
#' @param module The module under test
#' @param expr Test code containing expectations. The test expression will run
#' in the module's environment, meaning that the module's parameters (e.g.
#' `input`, `output`, and `session`) will be available along with any other
#' values created inside of the module.
#' @param ... Additional arguments to pass to the module function. These
#' arguments are processed with [rlang::list2()] and so are
#' _[dynamic][rlang::dyn-dots]_.
#' @param args A list of arguments to pass into the module beyond `input`,
#' `output`, and `session`.
#' @param initialState A list describing the initial values for `input`. If no
#' initial state is given, `input` will initialize as an empty list.
#' @param ... Additional named arguments to be passed on to the module function.
#' @include mock-session.R
#' @rdname testModule
#' @examples
#' module <- function(input, output, session, multiplier = 2, prefix = "I am ") {
#' myreactive <- reactive({
#' input$x * multiplier
#' })
#' output$txt <- renderText({
#' paste0(prefix, myreactive())
#' })
#' }
#'
#' # Basic Usage
#' # -----------
#' testModule(module, {
#' session$setInputs(x = 1)
#' # You're also free to use third-party
#' # testing packages like testthat:
#' # expect_equal(myreactive(), 2)
#' stopifnot(myreactive() == 2)
#' stopifnot(output$txt == "I am 2")
#'
#' session$setInputs(x = 2)
#' stopifnot(myreactive() == 4)
#' stopifnot(output$txt == "I am 4")
#' # Any additional arguments, below, are passed along to the module.
#' }, multiplier = 2)
#'
#' # Advanced Usage
#' # --------------
#' multiplier_arg_name = "multiplier"
#' more_args <- list(prefix = "I am ")
#' testModule(module, {
#' session$setInputs(x = 1)
#' stopifnot(myreactive() == 2)
#' stopifnot(output$txt == "I am 2")
#' # !!/:= and !!! from rlang are used below to splice computed arguments
#' # into the testModule() argument list.
#' }, !!multiplier_arg_name := 2, !!!more_args)
#' @export
testModule <- function(module, expr, ...) {
testModule <- function(module, expr, args, ...) {
expr <- substitute(expr)
.testModule(module, expr, ...)
.testModule(module, expr, args, ...)
}
#' @noRd
#' @importFrom withr with_options
.testModule <- function(module, expr, ...) {
.testModule <- function(module, expr, args, ...) {
# Capture the environment from the module
# Inserts `session$env <- environment()` at the top of the function
body(module) <- rlang::expr({
session$env <- environment()
!!!body(module)
})
fn_body <- body(module)
fn_body[seq(3, length(fn_body)+1)] <- fn_body[seq(2, length(fn_body))]
fn_body[[2]] <- quote(session$env <- environment())
body(module) <- fn_body
# Substitute expr for later evaluation
if (!is.call(expr)){
expr <- substitute(expr)
}
# Create a mock session
session <- MockShinySession$new()
# Parse the additional arguments
args <- rlang::list2(..., input = session$input, output = session$output, session = session)
args <- list(...)
args[["input"]] <- session$input
args[["output"]] <- session$output
args[["session"]] <- session
# Initialize the module
isolate(
@@ -94,7 +86,7 @@ testModule <- function(module, expr, ...) {
withReactiveDomain(
session,
withr::with_options(list(`shiny.allowoutputreads`=TRUE), {
eval(expr, new.env(parent=session$env))
eval(expr, session$env)
})
)
})
@@ -105,10 +97,10 @@ testModule <- function(module, expr, ...) {
}
#' Test an app's server-side logic
#' @param appDir The directory root of the Shiny application. If `NULL`, this function
#' @param expr Test code containing expectations
#' @param appdir The directory root of the Shiny application. If `NULL`, this function
#' will work up the directory hierarchy --- starting with the current directory ---
#' looking for a directory that contains an `app.R` or `server.R` file.
#' @rdname testModule
#' @export
testServer <- function(expr, appDir=NULL) {
if (is.null(appDir)){
@@ -116,13 +108,8 @@ testServer <- function(expr, appDir=NULL) {
}
app <- shinyAppDir(appDir)
message("Testing application found in: ", appDir)
server <- app$serverFuncSource()
origwd <- getwd()
setwd(appDir)
on.exit({ setwd(origwd) }, add=TRUE)
# Add `session` argument if not present
fn_formals <- formals(server)
if (! "session" %in% names(fn_formals)) {
@@ -130,6 +117,7 @@ testServer <- function(expr, appDir=NULL) {
formals(server) <- fn_formals
}
s3 <<- server
# Now test the server as we would a module
.testModule(server, expr=substitute(expr))
}

107
R/test.R
View File

@@ -1,107 +0,0 @@
#' Check to see if the given text is a shinytest
#' Scans for the magic string of `app <- ShinyDriver$new(` as an indicator that this is a shinytest.
#' Brought in from shinytest to avoid having to export this function.
#' @noRd
isShinyTest <- function(text){
lines <- grepl("app\\s*<-\\s*ShinyDriver\\$new\\(", text, perl=TRUE)
any(lines)
}
#' Runs the tests associated with this Shiny app
#'
#' Sources the `.R` files in the top-level of `tests/` much like `R CMD check`.
#' These files are typically simple runners for tests nested in other
#' directories under `tests/`.
#'
#' @param appDir The base directory for the application.
#' @param filter If not `NULL`, only tests with file names matching this regular
#' expression will be executed. Matching is performed on the file name
#' including the extension.
#'
#' @details Historically, [shinytest](https://rstudio.github.io/shinytest/)
#' recommended placing tests at the top-level of the `tests/` directory. In
#' order to support that model, `testApp` first checks to see if the `.R`
#' files in the `tests/` directory are all shinytests; if so, just calls out
#' to [shinytest::testApp()].
#' @export
runTests <- function(appDir=".", filter=NULL){
require(shiny)
testsDir <- file.path(appDir, "tests")
if (!dirExists(testsDir)){
stop("No tests directory found: ", testsDir)
}
runners <- list.files(testsDir, pattern="\\.r$", ignore.case = TRUE)
if (length(runners) == 0){
message("No test runners found in ", testsDir)
return(structure(list(result=NA, files=list()), class="shinytestrun"))
}
if (!is.null(filter)){
runners <- runners[grepl(filter, runners)]
}
if (length(runners) == 0){
stop("No test runners matched the given filter: '", filter, "'")
}
# Inspect each runner to see if it appears to be a shinytest
isST <- vapply(runners, function(r){
text <- readLines(file.path(testsDir, r), warn = FALSE)
isShinyTest(text)
}, logical(1))
if (all(isST)){
# just call out to shinytest
# We don't need to message/warn here since shinytest already does it.
if (!requireNamespace("shinytest", quietly=TRUE) ){
stop("It appears that the .R files in ", testsDir,
" are all shinytests, but shinytest is not installed.")
}
if (!getOption("shiny.autoload.r", TRUE)) {
warning("You've disabled `shiny.autoload.r` via an option but this is not passed through to shinytest. Consider using a _disable_autoload.R file as described at https://rstd.io/shiny-autoload")
}
sares <- shinytest::testApp(appDir)
res <- list()
lapply(sares$results, function(r){
e <- NA_character_
if (!r$pass){
e <- simpleError("Unknown shinytest error")
}
res[[r$name]] <<- e
})
return(structure(list(result=all(is.na(res)), files=res), class="shinytestrun"))
}
testenv <- new.env(parent=globalenv())
renv <- new.env(parent=testenv)
if (getOption("shiny.autoload.r", TRUE)) {
loadSupport(appDir, renv=renv, globalrenv=testenv)
} else if (file.exists.ci(file.path(appDir, "server.R"))){
# then check for global.R to load
if (file.exists(file.path.ci(appDir, "global.R"))){
sourceUTF8(file.path.ci(appDir, "global.R"))
}
}
oldwd <- getwd()
on.exit({
setwd(oldwd)
}, add=TRUE)
setwd(testsDir)
# Otherwise source all the runners -- each in their own environment.
fileResults <- list()
lapply(runners, function(r){
env <- new.env(parent=renv)
tryCatch({sourceUTF8(r, envir=env); fileResults[[r]] <<- NA_character_}, error=function(e){
fileResults[[r]] <<- e
})
})
return(structure(list(result=all(is.na(fileResults)), files=fileResults), class="shinytestrun"))
}

View File

@@ -1,9 +1,10 @@
# Return the current time, in milliseconds from epoch.
getTimeMs <- function() {
# Return the current time, in milliseconds from epoch, with
# unspecified time zone.
getNow <- function() {
as.numeric(Sys.time()) * 1000
}
TimerCallbacks <- R6Class(
BaseTimerCallbacks <- R6Class(
'TimerCallbacks',
portable = FALSE,
class = FALSE,
@@ -13,7 +14,7 @@ TimerCallbacks <- R6Class(
.times = data.frame(),
.now = 'Function',
initialize = function(nowFn = getTimeMs) {
initialize = function(nowFn=getNow) {
.funcs <<- Map$new()
.now <<- nowFn
},
@@ -61,7 +62,7 @@ TimerCallbacks <- R6Class(
},
takeElapsed = function() {
t <- .now()
elapsed <- .times$time <= .now()
elapsed <- .times$time <= t
result <- .times[elapsed,]
.times <<- .times[!elapsed,]
@@ -87,23 +88,36 @@ TimerCallbacks <- R6Class(
)
)
MockableTimerCallbacks <- R6Class(
'MockableTimerCallbacks',
inherit = TimerCallbacks,
TimerCallbacks <- R6Class(
'TimerCallbacks',
inherit=BaseTimerCallbacks,
portable = FALSE,
class = FALSE,
public = list(
# Empty constructor defaults to the getNow implementation
initialize = function() {
super$initialize(self$mockNow)
super$initialize(getNow)
}
)
)
MockableTimerCallbacks <- R6Class(
'MockableTimerCallbacks',
inherit=BaseTimerCallbacks,
portable = FALSE,
class = FALSE,
public = list(
# Empty constructor defaults to the getNow implementation
initialize = function() {
super$initialize(self$now)
},
mockNow = function() {
now = function(){
return(private$time)
},
elapse = function(millis) {
private$time <- private$time + millis
elapse = function(millis){
private$time <<- private$time + millis
},
getElapsed = function() {
getElapsed = function(){
private$time
}
), private = list(
@@ -126,22 +140,24 @@ scheduleTask <- function(millis, callback) {
#' session scheduler, but if it doesn't exist, use the global one.
#' @noRd
defineScheduler <- function(session){
if (!is.null(session) && !is.null(session$.scheduleTask)){
return(session$.scheduleTask)
if (!is.null(session)){
if (!is.null(session$scheduleTask)){
return(session$scheduleTask)
}
}
scheduleTask
}
#' Get the current time using the current reactive domain. This will try to use
#' the session's .now() method, but if that's not available, it will just return
#' the real time (from getTimeMs()). The purpose of this function is to allow
#' MockableTimerCallbacks to work.
#' Get the current time a la `Sys.time()`. Prefer to get it via the
#' `session$now()` function, but if that's not available, just return the
#' current system time.
#' @noRd
getDomainTimeMs <- function(session){
if (!is.null(session) && !is.null(session$.now)){
return(session$.now())
} else {
getTimeMs()
getTime <- function(session){
if (!is.null(session)){
if (!is.null(session$now)){
return(session$now())
}
}
Sys.time()
}

View File

@@ -11,16 +11,14 @@ install:
ps: Bootstrap
cache:
# Bust library cache every time the description file changes
# as appveyor cache can not be busted manually
# This helps get around errors such as "can't update curl because it's already loaded"
# when trying to update the existing cache
# PR: https://github.com/rstudio/shiny/pull/2722
- C:\RLibrary -> DESCRIPTION
- C:\RLibrary
# Adapt as necessary starting from here
build_script:
- travis-tool.sh install_github rstudio/htmltools@rc-v0.4.0
- travis-tool.sh install_github rstudio/promises@rc-v1.1.0
- travis-tool.sh install_github r-lib/later@rc-v1.0.0
- travis-tool.sh install_deps
test_script:

View File

@@ -77,6 +77,7 @@ reference:
- outputOptions
- tableOutput
- textOutput
- verbatimTextOutput
- downloadButton
- Progress
- withProgress
@@ -98,6 +99,7 @@ reference:
- bootstrapLib
- suppressDependencies
- insertUI
- removeUI
- title: Rendering functions
desc: Functions that you use in your application's server side code, assigning them to outputs that appear in your user interface.
contents:
@@ -216,6 +218,5 @@ reference:
- title: Testing
desc: Functions intended for testing of Shiny components
contents:
- runTests
- testModule
- MockShinySession
- testServer

View File

@@ -29,8 +29,8 @@ $.extend( true, DataTable.defaults, {
/* Default class modification */
$.extend( DataTable.ext.classes, {
sWrapper: "dataTables_wrapper form-inline dt-bootstrap",
sFilterInput: "form-control form-control-sm input-sm",
sLengthSelect: "form-control form-control-sm input-sm"
sFilterInput: "form-control input-sm",
sLengthSelect: "form-control input-sm"
} );

View File

@@ -401,9 +401,6 @@ pre.shiny-text-output {
/* Overrides bootstrap-datepicker3.css styling for invalid date ranges.
See https://github.com/rstudio/shiny/issues/2042 for details. */
.datepicker table tbody tr td.disabled,
.datepicker table tbody tr td.disabled:hover,
.datepicker table tbody tr td span.disabled,
.datepicker table tbody tr td span.disabled:hover {
.datepicker table tbody tr td.disabled:hover {
color: #aaa;
cursor: not-allowed;
}

View File

@@ -12,7 +12,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
var exports = window.Shiny = window.Shiny || {};
exports.version = "1.4.0.9001"; // Version number inserted by Grunt
exports.version = "1.4.0.9000"; // Version number inserted by Grunt
var origPushState = window.history.pushState;
window.history.pushState = function () {
@@ -1793,7 +1793,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
// Progress bar starts hidden; will be made visible if a value is provided
// during updates.
exports.notifications.show({
html: "<div id=\"shiny-progress-" + message.id + "\" class=\"shiny-progress-notification\">" + '<div class="progress active" style="display: none;"><div class="progress-bar"></div></div>' + '<div class="progress-text">' + '<span class="progress-message">message</span> ' + '<span class="progress-detail"></span>' + '</div>' + '</div>',
html: "<div id=\"shiny-progress-" + message.id + "\" class=\"shiny-progress-notification\">" + '<div class="progress progress-striped active" style="display: none;"><div class="progress-bar"></div></div>' + '<div class="progress-text">' + '<span class="progress-message">message</span> ' + '<span class="progress-detail"></span>' + '</div>' + '</div>',
id: message.id,
duration: null
});
@@ -1810,7 +1810,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
// Add div for just this progress ID
var depth = $('.shiny-progress.open').length;
// The 'bar' class is needed for backward compatibility with Bootstrap 2.
var $progress = $('<div class="shiny-progress open">' + '<div class="progress active"><div class="progress-bar bar"></div></div>' + '<div class="progress-text">' + '<span class="progress-message">message</span>' + '<span class="progress-detail"></span>' + '</div>' + '</div>');
var $progress = $('<div class="shiny-progress open">' + '<div class="progress progress-striped active"><div class="progress-bar bar"></div></div>' + '<div class="progress-text">' + '<span class="progress-message">message</span>' + '<span class="progress-detail"></span>' + '</div>' + '</div>');
$progress.attr('id', message.id);
$container.append($progress);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,642 +0,0 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/mock-session.R
\name{MockShinySession}
\alias{MockShinySession}
\title{Mock Shiny Session}
\description{
An R6 class suitable for testing that simulates the \code{session} parameter
provided to Shiny server functions or modules.
}
\examples{
## ------------------------------------------------
## Method `MockShinySession$setInputs`
## ------------------------------------------------
s <- MockShinySession$new()
s$setInputs(x=1, y=2)
}
\section{Public fields}{
\if{html}{\out{<div class="r6-fields">}}
\describe{
\item{\code{env}}{The environment associated with the session.}
\item{\code{singletons}}{Hardcoded as empty. Needed for rendering HTML (i.e. renderUI)}
\item{\code{clientData}}{Mock client data that always returns a size for plots}
\item{\code{output}}{The shinyoutputs associated with the session}
\item{\code{input}}{The reactive inputs associated with the session}
\item{\code{userData}}{An environment initialized as empty.}
\item{\code{progressStack}}{A stack of progress objects}
}
\if{html}{\out{</div>}}
}
\section{Active bindings}{
\if{html}{\out{<div class="r6-active-bindings">}}
\describe{
\item{\code{returned}}{The value returned from the module}
\item{\code{request}}{An empty environment where the request should be. The request isn't meaningfully mocked currently.}
}
\if{html}{\out{</div>}}
}
\section{Methods}{
\subsection{Public methods}{
\itemize{
\item \href{#method-reactlog}{\code{MockShinySession$reactlog()}}
\item \href{#method-incrementBusyCount}{\code{MockShinySession$incrementBusyCount()}}
\item \href{#method-new}{\code{MockShinySession$new()}}
\item \href{#method-onFlush}{\code{MockShinySession$onFlush()}}
\item \href{#method-onFlushed}{\code{MockShinySession$onFlushed()}}
\item \href{#method-onEnded}{\code{MockShinySession$onEnded()}}
\item \href{#method-isEnded}{\code{MockShinySession$isEnded()}}
\item \href{#method-isClosed}{\code{MockShinySession$isClosed()}}
\item \href{#method-close}{\code{MockShinySession$close()}}
\item \href{#method-cycleStartAction}{\code{MockShinySession$cycleStartAction()}}
\item \href{#method-fileUrl}{\code{MockShinySession$fileUrl()}}
\item \href{#method-setInputs}{\code{MockShinySession$setInputs()}}
\item \href{#method-.scheduleTask}{\code{MockShinySession$.scheduleTask()}}
\item \href{#method-elapse}{\code{MockShinySession$elapse()}}
\item \href{#method-.now}{\code{MockShinySession$.now()}}
\item \href{#method-defineOutput}{\code{MockShinySession$defineOutput()}}
\item \href{#method-getOutput}{\code{MockShinySession$getOutput()}}
\item \href{#method-registerDataObj}{\code{MockShinySession$registerDataObj()}}
\item \href{#method-allowReconnect}{\code{MockShinySession$allowReconnect()}}
\item \href{#method-reload}{\code{MockShinySession$reload()}}
\item \href{#method-resetBrush}{\code{MockShinySession$resetBrush()}}
\item \href{#method-sendCustomMessage}{\code{MockShinySession$sendCustomMessage()}}
\item \href{#method-sendBinaryMessage}{\code{MockShinySession$sendBinaryMessage()}}
\item \href{#method-sendInputMessage}{\code{MockShinySession$sendInputMessage()}}
\item \href{#method-setBookmarkExclude}{\code{MockShinySession$setBookmarkExclude()}}
\item \href{#method-getBookmarkExclude}{\code{MockShinySession$getBookmarkExclude()}}
\item \href{#method-onBookmark}{\code{MockShinySession$onBookmark()}}
\item \href{#method-onBookmarked}{\code{MockShinySession$onBookmarked()}}
\item \href{#method-doBookmark}{\code{MockShinySession$doBookmark()}}
\item \href{#method-onRestore}{\code{MockShinySession$onRestore()}}
\item \href{#method-onRestored}{\code{MockShinySession$onRestored()}}
\item \href{#method-exportTestValues}{\code{MockShinySession$exportTestValues()}}
\item \href{#method-getTestSnapshotUrl}{\code{MockShinySession$getTestSnapshotUrl()}}
\item \href{#method-ns}{\code{MockShinySession$ns()}}
\item \href{#method-flushReact}{\code{MockShinySession$flushReact()}}
\item \href{#method-makeScope}{\code{MockShinySession$makeScope()}}
\item \href{#method-clone}{\code{MockShinySession$clone()}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-reactlog"></a>}}
\subsection{Method \code{reactlog()}}{
No-op
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$reactlog(logEntry)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{logEntry}}{Not used}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-incrementBusyCount"></a>}}
\subsection{Method \code{incrementBusyCount()}}{
No-op
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$incrementBusyCount()}\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-new"></a>}}
\subsection{Method \code{new()}}{
Create a new MockShinySession
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$new()}\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-onFlush"></a>}}
\subsection{Method \code{onFlush()}}{
Define a callback to be invoked before a reactive flush
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$onFlush(fun, once = TRUE)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{fun}}{The function to invoke}
\item{\code{once}}{If \code{TRUE}, will only run once. Otherwise, will run every time reactives are flushed.}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-onFlushed"></a>}}
\subsection{Method \code{onFlushed()}}{
Define a callback to be invoked after a reactive flush
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$onFlushed(fun, once = TRUE)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{fun}}{The function to invoke}
\item{\code{once}}{If \code{TRUE}, will only run once. Otherwise, will run every time reactives are flushed.}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-onEnded"></a>}}
\subsection{Method \code{onEnded()}}{
Define a callback to be invoked when the session ends
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$onEnded(sessionEndedCallback)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{sessionEndedCallback}}{The callback to invoke when the session has ended.}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-isEnded"></a>}}
\subsection{Method \code{isEnded()}}{
Returns \code{FALSE} if the session has not yet been closed
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$isEnded()}\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-isClosed"></a>}}
\subsection{Method \code{isClosed()}}{
Returns \code{FALSE} if the session has not yet been closed
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$isClosed()}\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-close"></a>}}
\subsection{Method \code{close()}}{
Closes the session
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$close()}\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-cycleStartAction"></a>}}
\subsection{Method \code{cycleStartAction()}}{
Unsophisticated mock implementation that merely invokes
the given callback immediately.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$cycleStartAction(callback)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{callback}}{The callback ato be invoked.}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-fileUrl"></a>}}
\subsection{Method \code{fileUrl()}}{
Base64-encode the given file. Needed for image rendering.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$fileUrl(name, file, contentType = "application/octet-stream")}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{name}}{Not used}
\item{\code{file}}{The file to be encoded}
\item{\code{contentType}}{The content type of the base64-encoded string}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-setInputs"></a>}}
\subsection{Method \code{setInputs()}}{
Sets reactive values associated with the \code{session$inputs} object
and flushes the reactives.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$setInputs(...)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{...}}{The inputs to set.}
}
\if{html}{\out{</div>}}
}
\subsection{Examples}{
\if{html}{\out{<div class="r example copy">}}
\preformatted{s <- MockShinySession$new()
s$setInputs(x=1, y=2)
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-.scheduleTask"></a>}}
\subsection{Method \code{.scheduleTask()}}{
An internal method which shouldn't be used by others.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$.scheduleTask(millis, callback)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{millis}}{The number of milliseconds on which to schedule a callback}
\item{\code{callback}}{The function to schedule}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-elapse"></a>}}
\subsection{Method \code{elapse()}}{
Simulate the passing of time by the given number of milliseconds.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$elapse(millis)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{millis}}{The number of milliseconds to advance time.}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-.now"></a>}}
\subsection{Method \code{.now()}}{
An internal method which shouldn't be used by others.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$.now()}\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-defineOutput"></a>}}
\subsection{Method \code{defineOutput()}}{
An internal method which shouldn't be used by others.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$defineOutput(name, func, label)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{name}}{The name of the output}
\item{\code{func}}{The render definition}
\item{\code{label}}{Not used}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-getOutput"></a>}}
\subsection{Method \code{getOutput()}}{
An internal method which shouldn't be used by others.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$getOutput(name)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{name}}{The name of the output}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-registerDataObj"></a>}}
\subsection{Method \code{registerDataObj()}}{
No-op
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$registerDataObj(name, data, filterFunc)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{name}}{Not used}
\item{\code{data}}{Not used}
\item{\code{filterFunc}}{Not used}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-allowReconnect"></a>}}
\subsection{Method \code{allowReconnect()}}{
No-op
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$allowReconnect(value)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{value}}{Not used}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-reload"></a>}}
\subsection{Method \code{reload()}}{
No-op
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$reload()}\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-resetBrush"></a>}}
\subsection{Method \code{resetBrush()}}{
No-op
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$resetBrush(brushId)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{brushId}}{Not used}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-sendCustomMessage"></a>}}
\subsection{Method \code{sendCustomMessage()}}{
No-op
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$sendCustomMessage(type, message)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{type}}{Not used}
\item{\code{message}}{Not used}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-sendBinaryMessage"></a>}}
\subsection{Method \code{sendBinaryMessage()}}{
No-op
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$sendBinaryMessage(type, message)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{type}}{Not used}
\item{\code{message}}{Not used}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-sendInputMessage"></a>}}
\subsection{Method \code{sendInputMessage()}}{
No-op
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$sendInputMessage(inputId, message)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{inputId}}{Not used}
\item{\code{message}}{Not used}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-setBookmarkExclude"></a>}}
\subsection{Method \code{setBookmarkExclude()}}{
No-op
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$setBookmarkExclude(names)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{names}}{Not used}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-getBookmarkExclude"></a>}}
\subsection{Method \code{getBookmarkExclude()}}{
No-op
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$getBookmarkExclude()}\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-onBookmark"></a>}}
\subsection{Method \code{onBookmark()}}{
No-op
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$onBookmark(fun)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{fun}}{Not used}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-onBookmarked"></a>}}
\subsection{Method \code{onBookmarked()}}{
No-op
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$onBookmarked(fun)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{fun}}{Not used}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-doBookmark"></a>}}
\subsection{Method \code{doBookmark()}}{
No-op
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$doBookmark()}\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-onRestore"></a>}}
\subsection{Method \code{onRestore()}}{
No-op
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$onRestore(fun)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{fun}}{Not used}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-onRestored"></a>}}
\subsection{Method \code{onRestored()}}{
No-op
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$onRestored(fun)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{fun}}{Not used}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-exportTestValues"></a>}}
\subsection{Method \code{exportTestValues()}}{
No-op
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$exportTestValues()}\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-getTestSnapshotUrl"></a>}}
\subsection{Method \code{getTestSnapshotUrl()}}{
No-op
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$getTestSnapshotUrl(
input = TRUE,
output = TRUE,
export = TRUE,
format = "json"
)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{input}}{Not used}
\item{\code{output}}{Not used}
\item{\code{export}}{Not used}
\item{\code{format}}{Not used}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-ns"></a>}}
\subsection{Method \code{ns()}}{
Returns the given id prefixed by \verb{mock-session-}.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$ns(id)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{id}}{The id to modify.}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-flushReact"></a>}}
\subsection{Method \code{flushReact()}}{
Trigger a reactive flush right now.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$flushReact()}\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-makeScope"></a>}}
\subsection{Method \code{makeScope()}}{
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$makeScope(namespace)}\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-clone"></a>}}
\subsection{Method \code{clone()}}{
The objects of this class are cloneable with this method.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$clone(deep = FALSE)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{deep}}{Whether to make a deep clone.}
}
\if{html}{\out{</div>}}
}
}
}

View File

@@ -1,16 +1,47 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/progress.R
\docType{data}
\name{Progress}
\alias{Progress}
\title{Reporting progress (object-oriented API)}
\description{
Reporting progress (object-oriented API)
\arguments{
\item{session}{The Shiny session object, as provided by
\code{shinyServer} to the server function.}
Reporting progress (object-oriented API)
\item{min}{The value that represents the starting point of the
progress bar. Must be less than \code{max}.}
\item{max}{The value that represents the end of the progress bar.
Must be greater than \code{min}.}
\item{message}{A single-element character vector; the message to be
displayed to the user, or \code{NULL} to hide the current message
(if any).}
\item{detail}{A single-element character vector; the detail message
to be displayed to the user, or \code{NULL} to hide the current
detail message (if any). The detail message will be shown with a
de-emphasized appearance relative to \code{message}.}
\item{value}{A numeric value at which to set
the progress bar, relative to \code{min} and \code{max}.}
\item{style}{Progress display style. If \code{"notification"} (the default),
the progress indicator will show using Shiny's notification API. If
\code{"old"}, use the same HTML and CSS used in Shiny 0.13.2 and below
(this is for backward-compatibility).}
\item{amount}{Single-element numeric vector; the value at which to set
the progress bar, relative to \code{min} and \code{max}.
\code{NULL} hides the progress bar, if it is currently visible.}
\item{amount}{For the \code{inc()} method, a numeric value to increment the
progress bar.}
}
\description{
Reports progress to the user during long-running operations.
}
\details{
Reports progress to the user during long-running operations.
This package exposes two distinct programming APIs for working with
progress. \code{\link[=withProgress]{withProgress()}} and \code{\link[=setProgress]{setProgress()}}
together provide a simple function-based interface, while the
@@ -28,6 +59,26 @@ CSS), you can use \code{style="old"} each time you call
\code{Progress$new} is called, you can instead call
\code{\link[=shinyOptions]{shinyOptions(progress.style="old")}} just once, inside the server
function.
\strong{Methods}
\describe{
\item{\code{initialize(session, min = 0, max = 1)}}{
Creates a new progress panel (but does not display it).
}
\item{\code{set(value = NULL, message = NULL, detail = NULL)}}{
Updates the progress panel. When called the first time, the
progress panel is displayed.
}
\item{\code{inc(amount = 0.1, message = NULL, detail = NULL)}}{
Like \code{set}, this updates the progress panel. The difference is
that \code{inc} increases the progress bar by \code{amount}, instead
of setting it to a specific value.
}
\item{\code{close()}}{
Removes the progress panel. Future calls to \code{set} and
\code{close} will be ignored.
}
}
}
\examples{
## Only run examples in interactive R sessions
@@ -59,157 +110,4 @@ shinyApp(ui, server)
\seealso{
\code{\link[=withProgress]{withProgress()}}
}
\section{Methods}{
\subsection{Public methods}{
\itemize{
\item \href{#method-new}{\code{Progress$new()}}
\item \href{#method-set}{\code{Progress$set()}}
\item \href{#method-inc}{\code{Progress$inc()}}
\item \href{#method-getMin}{\code{Progress$getMin()}}
\item \href{#method-getMax}{\code{Progress$getMax()}}
\item \href{#method-getValue}{\code{Progress$getValue()}}
\item \href{#method-close}{\code{Progress$close()}}
\item \href{#method-clone}{\code{Progress$clone()}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-new"></a>}}
\subsection{Method \code{new()}}{
Creates a new progress panel (but does not display it).
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{Progress$new(
session = getDefaultReactiveDomain(),
min = 0,
max = 1,
style = getShinyOption("progress.style", default = "notification")
)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{session}}{The Shiny session object, as provided by \code{shinyServer} to
the server function.}
\item{\code{min}}{The value that represents the starting point of the progress
bar. Must be less than \code{max}.}
\item{\code{max}}{The value that represents the end of the progress bar. Must be
greater than \code{min}.}
\item{\code{style}}{Progress display style. If \code{"notification"} (the default),
the progress indicator will show using Shiny's notification API. If
\code{"old"}, use the same HTML and CSS used in Shiny 0.13.2 and below (this
is for backward-compatibility).}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-set"></a>}}
\subsection{Method \code{set()}}{
Updates the progress panel. When called the first time, the
progress panel is displayed.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{Progress$set(value = NULL, message = NULL, detail = NULL)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{value}}{Single-element numeric vector; the value at which to set the
progress bar, relative to \code{min} and \code{max}. \code{NULL} hides the progress
bar, if it is currently visible.}
\item{\code{message}}{A single-element character vector; the message to be
displayed to the user, or \code{NULL} to hide the current message (if any).}
\item{\code{detail}}{A single-element character vector; the detail message to be
displayed to the user, or \code{NULL} to hide the current detail message (if
any). The detail message will be shown with a de-emphasized appearance
relative to \code{message}.}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-inc"></a>}}
\subsection{Method \code{inc()}}{
Like \code{set}, this updates the progress panel. The difference
is that \code{inc} increases the progress bar by \code{amount}, instead of
setting it to a specific value.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{Progress$inc(amount = 0.1, message = NULL, detail = NULL)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{amount}}{For the \code{inc()} method, a numeric value to increment the
progress bar.}
\item{\code{message}}{A single-element character vector; the message to be
displayed to the user, or \code{NULL} to hide the current message (if any).}
\item{\code{detail}}{A single-element character vector; the detail message to be
displayed to the user, or \code{NULL} to hide the current detail message (if
any). The detail message will be shown with a de-emphasized appearance
relative to \code{message}.}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-getMin"></a>}}
\subsection{Method \code{getMin()}}{
Returns the minimum value.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{Progress$getMin()}\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-getMax"></a>}}
\subsection{Method \code{getMax()}}{
Returns the maximum value.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{Progress$getMax()}\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-getValue"></a>}}
\subsection{Method \code{getValue()}}{
Returns the current value.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{Progress$getValue()}\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-close"></a>}}
\subsection{Method \code{close()}}{
Removes the progress panel. Future calls to \code{set} and
\code{close} will be ignored.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{Progress$close()}\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-clone"></a>}}
\subsection{Method \code{clone()}}{
The objects of this class are cloneable with this method.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{Progress$clone(deep = FALSE)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{deep}}{Whether to make a deep clone.}
}
\if{html}{\out{</div>}}
}
}
}
\keyword{datasets}

View File

@@ -5,30 +5,13 @@
\alias{fixedPanel}
\title{Panel with absolute positioning}
\usage{
absolutePanel(
...,
top = NULL,
left = NULL,
right = NULL,
bottom = NULL,
width = NULL,
height = NULL,
draggable = FALSE,
fixed = FALSE,
cursor = c("auto", "move", "default", "inherit")
)
absolutePanel(..., top = NULL, left = NULL, right = NULL,
bottom = NULL, width = NULL, height = NULL, draggable = FALSE,
fixed = FALSE, cursor = c("auto", "move", "default", "inherit"))
fixedPanel(
...,
top = NULL,
left = NULL,
right = NULL,
bottom = NULL,
width = NULL,
height = NULL,
draggable = FALSE,
cursor = c("auto", "move", "default", "inherit")
)
fixedPanel(..., top = NULL, left = NULL, right = NULL,
bottom = NULL, width = NULL, height = NULL, draggable = FALSE,
cursor = c("auto", "move", "default", "inherit"))
}
\arguments{
\item{...}{Attributes (named arguments) or children (unnamed arguments) that
@@ -70,7 +53,7 @@ An HTML element or list of elements.
Creates a panel whose contents are absolutely positioned.
}
\details{
The \code{absolutePanel} function creates a \verb{<div>} tag whose CSS
The \code{absolutePanel} function creates a \code{<div>} tag whose CSS
position is set to \code{absolute} (or fixed if \code{fixed = TRUE}). The way
absolute positioning works in HTML is that absolute coordinates are specified
relative to its nearest parent element whose position is not set to

View File

@@ -67,20 +67,13 @@ shinyApp(ui, server)
\seealso{
\code{\link[=observeEvent]{observeEvent()}} and \code{\link[=eventReactive]{eventReactive()}}
Other input elements:
\code{\link{checkboxGroupInput}()},
\code{\link{checkboxInput}()},
\code{\link{dateInput}()},
\code{\link{dateRangeInput}()},
\code{\link{fileInput}()},
\code{\link{numericInput}()},
\code{\link{passwordInput}()},
\code{\link{radioButtons}()},
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}
Other input elements: \code{\link{checkboxGroupInput}},
\code{\link{checkboxInput}}, \code{\link{dateInput}},
\code{\link{dateRangeInput}}, \code{\link{fileInput}},
\code{\link{numericInput}}, \code{\link{passwordInput}},
\code{\link{radioButtons}}, \code{\link{selectInput}},
\code{\link{sliderInput}}, \code{\link{submitButton}},
\code{\link{textAreaInput}}, \code{\link{textInput}},
\code{\link{varSelectInput}}
}
\concept{input elements}

View File

@@ -4,13 +4,10 @@
\alias{bookmarkButton}
\title{Create a button for bookmarking/sharing}
\usage{
bookmarkButton(
label = "Bookmark...",
icon = shiny::icon("link", lib = "glyphicon"),
bookmarkButton(label = "Bookmark...", icon = shiny::icon("link", lib =
"glyphicon"),
title = "Bookmark this application's state and get a URL for sharing.",
...,
id = "._bookmark_"
)
..., id = "._bookmark_")
}
\arguments{
\item{label}{The contents of the button or link--usually a text label, but

View File

@@ -4,17 +4,9 @@
\alias{brushOpts}
\title{Create an object representing brushing options}
\usage{
brushOpts(
id = NULL,
fill = "#9cf",
stroke = "#036",
opacity = 0.25,
delay = 300,
delayType = c("debounce", "throttle"),
clip = TRUE,
direction = c("xy", "x", "y"),
resetOnNew = FALSE
)
brushOpts(id = NULL, fill = "#9cf", stroke = "#036",
opacity = 0.25, delay = 300, delayType = c("debounce", "throttle"),
clip = TRUE, direction = c("xy", "x", "y"), resetOnNew = FALSE)
}
\arguments{
\item{id}{Input value name. For example, if the value is \code{"plot_brush"},

View File

@@ -4,15 +4,8 @@
\alias{brushedPoints}
\title{Find rows of data that are selected by a brush}
\usage{
brushedPoints(
df,
brush,
xvar = NULL,
yvar = NULL,
panelvar1 = NULL,
panelvar2 = NULL,
allRows = FALSE
)
brushedPoints(df, brush, xvar = NULL, yvar = NULL, panelvar1 = NULL,
panelvar2 = NULL, allRows = FALSE)
}
\arguments{
\item{df}{A data frame from which to select rows.}

31
man/callModule.Rd Normal file
View File

@@ -0,0 +1,31 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/modules.R
\name{callModule}
\alias{callModule}
\title{Invoke a Shiny module}
\usage{
callModule(module, id, ..., session = getDefaultReactiveDomain())
}
\arguments{
\item{module}{A Shiny module server function}
\item{id}{An ID string that corresponds with the ID used to call the module's
UI function}
\item{...}{Additional parameters to pass to module server function}
\item{session}{Session from which to make a child scope (the default should
almost always be used)}
}
\value{
The return value, if any, from executing the module server function
}
\description{
Shiny's module feature lets you break complicated UI and server logic into
smaller, self-contained pieces. Compared to large monolithic Shiny apps,
modules are easier to reuse and easier to reason about. See the article at
\url{http://shiny.rstudio.com/articles/modules.html} to learn more.
}
\seealso{
\url{http://shiny.rstudio.com/articles/modules.html}
}

View File

@@ -4,16 +4,9 @@
\alias{checkboxGroupInput}
\title{Checkbox Group Input Control}
\usage{
checkboxGroupInput(
inputId,
label,
choices = NULL,
selected = NULL,
inline = FALSE,
width = NULL,
choiceNames = NULL,
choiceValues = NULL
)
checkboxGroupInput(inputId, label, choices = NULL, selected = NULL,
inline = FALSE, width = NULL, choiceNames = NULL,
choiceValues = NULL)
}
\arguments{
\item{inputId}{The \code{input} slot that will be used to access the value.}
@@ -100,20 +93,13 @@ shinyApp(ui, server)
\seealso{
\code{\link[=checkboxInput]{checkboxInput()}}, \code{\link[=updateCheckboxGroupInput]{updateCheckboxGroupInput()}}
Other input elements:
\code{\link{actionButton}()},
\code{\link{checkboxInput}()},
\code{\link{dateInput}()},
\code{\link{dateRangeInput}()},
\code{\link{fileInput}()},
\code{\link{numericInput}()},
\code{\link{passwordInput}()},
\code{\link{radioButtons}()},
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}
Other input elements: \code{\link{actionButton}},
\code{\link{checkboxInput}}, \code{\link{dateInput}},
\code{\link{dateRangeInput}}, \code{\link{fileInput}},
\code{\link{numericInput}}, \code{\link{passwordInput}},
\code{\link{radioButtons}}, \code{\link{selectInput}},
\code{\link{sliderInput}}, \code{\link{submitButton}},
\code{\link{textAreaInput}}, \code{\link{textInput}},
\code{\link{varSelectInput}}
}
\concept{input elements}

View File

@@ -45,20 +45,13 @@ shinyApp(ui, server)
\seealso{
\code{\link[=checkboxGroupInput]{checkboxGroupInput()}}, \code{\link[=updateCheckboxInput]{updateCheckboxInput()}}
Other input elements:
\code{\link{actionButton}()},
\code{\link{checkboxGroupInput}()},
\code{\link{dateInput}()},
\code{\link{dateRangeInput}()},
\code{\link{fileInput}()},
\code{\link{numericInput}()},
\code{\link{passwordInput}()},
\code{\link{radioButtons}()},
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}
Other input elements: \code{\link{actionButton}},
\code{\link{checkboxGroupInput}},
\code{\link{dateInput}}, \code{\link{dateRangeInput}},
\code{\link{fileInput}}, \code{\link{numericInput}},
\code{\link{passwordInput}}, \code{\link{radioButtons}},
\code{\link{selectInput}}, \code{\link{sliderInput}},
\code{\link{submitButton}}, \code{\link{textAreaInput}},
\code{\link{textInput}}, \code{\link{varSelectInput}}
}
\concept{input elements}

View File

@@ -4,12 +4,8 @@
\alias{createRenderFunction}
\title{Implement render functions}
\usage{
createRenderFunction(
func,
transform = function(value, session, name, ...) value,
outputFunc = NULL,
outputArgs = NULL
)
createRenderFunction(func, transform = function(value, session, name,
...) value, outputFunc = NULL, outputArgs = NULL)
}
\arguments{
\item{func}{A function without parameters, that returns user data. If the

View File

@@ -4,21 +4,10 @@
\alias{dateInput}
\title{Create date input}
\usage{
dateInput(
inputId,
label,
value = NULL,
min = NULL,
max = NULL,
format = "yyyy-mm-dd",
startview = "month",
weekstart = 0,
language = "en",
width = NULL,
autoclose = TRUE,
datesdisabled = NULL,
daysofweekdisabled = NULL
)
dateInput(inputId, label, value = NULL, min = NULL, max = NULL,
format = "yyyy-mm-dd", startview = "month", weekstart = 0,
language = "en", width = NULL, autoclose = TRUE,
datesdisabled = NULL, daysofweekdisabled = NULL)
}
\arguments{
\item{inputId}{The \code{input} slot that will be used to access the value.}
@@ -131,20 +120,14 @@ shinyApp(ui, server = function(input, output) { })
\seealso{
\code{\link[=dateRangeInput]{dateRangeInput()}}, \code{\link[=updateDateInput]{updateDateInput()}}
Other input elements:
\code{\link{actionButton}()},
\code{\link{checkboxGroupInput}()},
\code{\link{checkboxInput}()},
\code{\link{dateRangeInput}()},
\code{\link{fileInput}()},
\code{\link{numericInput}()},
\code{\link{passwordInput}()},
\code{\link{radioButtons}()},
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}
Other input elements: \code{\link{actionButton}},
\code{\link{checkboxGroupInput}},
\code{\link{checkboxInput}},
\code{\link{dateRangeInput}}, \code{\link{fileInput}},
\code{\link{numericInput}}, \code{\link{passwordInput}},
\code{\link{radioButtons}}, \code{\link{selectInput}},
\code{\link{sliderInput}}, \code{\link{submitButton}},
\code{\link{textAreaInput}}, \code{\link{textInput}},
\code{\link{varSelectInput}}
}
\concept{input elements}

View File

@@ -4,21 +4,10 @@
\alias{dateRangeInput}
\title{Create date range input}
\usage{
dateRangeInput(
inputId,
label,
start = NULL,
end = NULL,
min = NULL,
max = NULL,
format = "yyyy-mm-dd",
startview = "month",
weekstart = 0,
language = "en",
separator = " to ",
width = NULL,
autoclose = TRUE
)
dateRangeInput(inputId, label, start = NULL, end = NULL, min = NULL,
max = NULL, format = "yyyy-mm-dd", startview = "month",
weekstart = 0, language = "en", separator = " to ", width = NULL,
autoclose = TRUE)
}
\arguments{
\item{inputId}{The \code{input} slot that will be used to access the value.}
@@ -135,20 +124,13 @@ shinyApp(ui, server = function(input, output) { })
\seealso{
\code{\link[=dateInput]{dateInput()}}, \code{\link[=updateDateRangeInput]{updateDateRangeInput()}}
Other input elements:
\code{\link{actionButton}()},
\code{\link{checkboxGroupInput}()},
\code{\link{checkboxInput}()},
\code{\link{dateInput}()},
\code{\link{fileInput}()},
\code{\link{numericInput}()},
\code{\link{passwordInput}()},
\code{\link{radioButtons}()},
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}
Other input elements: \code{\link{actionButton}},
\code{\link{checkboxGroupInput}},
\code{\link{checkboxInput}}, \code{\link{dateInput}},
\code{\link{fileInput}}, \code{\link{numericInput}},
\code{\link{passwordInput}}, \code{\link{radioButtons}},
\code{\link{selectInput}}, \code{\link{sliderInput}},
\code{\link{submitButton}}, \code{\link{textAreaInput}},
\code{\link{textInput}}, \code{\link{varSelectInput}}
}
\concept{input elements}

View File

@@ -5,9 +5,11 @@
\alias{throttle}
\title{Slow down a reactive expression with debounce/throttle}
\usage{
debounce(r, millis, priority = 100, domain = getDefaultReactiveDomain())
debounce(r, millis, priority = 100,
domain = getDefaultReactiveDomain())
throttle(r, millis, priority = 100, domain = getDefaultReactiveDomain())
throttle(r, millis, priority = 100,
domain = getDefaultReactiveDomain())
}
\arguments{
\item{r}{A reactive expression (that invalidates too often).}
@@ -47,7 +49,7 @@ continually arrive from \code{r} within the time window, the debounced
reactive will not invalidate at all. Only after the invalidations stop (or
slow down sufficiently) will the downstream invalidation be sent.
\verb{ooo-oo-oo---- => -----------o-}
\code{ooo-oo-oo---- => -----------o-}
(In this graphical depiction, each character represents a unit of time, and
the time window is 3 characters.)
@@ -59,7 +61,7 @@ continually come from \code{r} within the time window, the throttled reactive
will invalidate regularly, at a rate equal to or slower than than the time
window.
\verb{ooo-oo-oo---- => o--o--o--o---}
\code{ooo-oo-oo---- => o--o--o--o---}
}
\section{Limitations}{

View File

@@ -4,17 +4,9 @@
\alias{diskCache}
\title{Create a disk cache object}
\usage{
diskCache(
dir = NULL,
max_size = 10 * 1024^2,
max_age = Inf,
max_n = Inf,
evict = c("lru", "fifo"),
destroy_on_finalize = FALSE,
missing = key_missing(),
exec_missing = FALSE,
logfile = NULL
)
diskCache(dir = NULL, max_size = 10 * 1024^2, max_age = Inf,
max_n = Inf, evict = c("lru", "fifo"), destroy_on_finalize = FALSE,
missing = key_missing(), exec_missing = FALSE, logfile = NULL)
}
\arguments{
\item{dir}{Directory to store files for the cache. If \code{NULL} (the

View File

@@ -4,7 +4,8 @@
\alias{downloadHandler}
\title{File Downloads}
\usage{
downloadHandler(filename, content, contentType = NA, outputArgs = list())
downloadHandler(filename, content, contentType = NA,
outputArgs = list())
}
\arguments{
\item{filename}{A string of the filename, including extension, that the

View File

@@ -4,12 +4,8 @@
\alias{exportTestValues}
\title{Register expressions for export in test mode}
\usage{
exportTestValues(
...,
quoted_ = FALSE,
env_ = parent.frame(),
session_ = getDefaultReactiveDomain()
)
exportTestValues(..., quoted_ = FALSE, env_ = parent.frame(),
session_ = getDefaultReactiveDomain())
}
\arguments{
\item{...}{Named arguments that are quoted or unquoted expressions that will
@@ -66,7 +62,7 @@ shinyApp(
})
output$values <- renderText({
paste0("vals$x: ", vals$x, "\ny: ", y())
paste0("vals$x: ", vals$x, "\\ny: ", y())
})
}
)

View File

@@ -4,15 +4,9 @@
\alias{fileInput}
\title{File Upload Control}
\usage{
fileInput(
inputId,
label,
multiple = FALSE,
accept = NULL,
width = NULL,
buttonLabel = "Browse...",
placeholder = "No file selected"
)
fileInput(inputId, label, multiple = FALSE, accept = NULL,
width = NULL, buttonLabel = "Browse...",
placeholder = "No file selected")
}
\arguments{
\item{inputId}{The \code{input} slot that will be used to access the value.}
@@ -23,17 +17,8 @@ fileInput(
multiple files at once. \strong{Does not work on older browsers, including
Internet Explorer 9 and earlier.}}
\item{accept}{A character vector of "unique file type specifiers" which
gives the browser a hint as to the type of file the server expects.
Many browsers use this prevent the user from selecting an invalid file.
A unique file type specifier can be:
\itemize{
\item A case insensitive extension like \code{.csv} or \code{.rds}.
\item A valid MIME type, like \code{text/plain} or \code{application/pdf}
\item One of \verb{audio/*}, \verb{video/*}, or \verb{image/*} meaning any audio, video,
or image type, respectively.
}}
\item{accept}{A character vector of MIME types; gives the browser a hint of
what kind of files the server is expecting.}
\item{width}{The width of the input, e.g. \code{'400px'}, or \code{'100\%'};
see \code{\link[=validateCssUnit]{validateCssUnit()}}.}
@@ -48,7 +33,7 @@ Create a file upload control that can be used to upload one or more files.
}
\details{
Whenever a file upload completes, the corresponding input variable is set
to a dataframe. See the \verb{Server value} section.
to a dataframe. See the \code{Server value} section.
}
\section{Server value}{
@@ -75,7 +60,13 @@ if (interactive()) {
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File", accept = ".csv"),
fileInput("file1", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
tags$hr(),
checkboxInput("header", "Header", TRUE)
),
mainPanel(
@@ -86,13 +77,17 @@ ui <- fluidPage(
server <- function(input, output) {
output$contents <- renderTable({
file <- input$file1
ext <- tools::file_ext(file$datapath)
# input$file1 will be NULL initially. After the user selects
# and uploads a file, it will be a data frame with 'name',
# 'size', 'type', and 'datapath' columns. The 'datapath'
# column will contain the local filenames where the data can
# be found.
inFile <- input$file1
req(file)
validate(need(ext == "csv", "Please upload a csv file"))
if (is.null(inFile))
return(NULL)
read.csv(file$datapath, header = input$header)
read.csv(inFile$datapath, header = input$header)
})
}
@@ -101,20 +96,13 @@ shinyApp(ui, server)
}
\seealso{
Other input elements:
\code{\link{actionButton}()},
\code{\link{checkboxGroupInput}()},
\code{\link{checkboxInput}()},
\code{\link{dateInput}()},
\code{\link{dateRangeInput}()},
\code{\link{numericInput}()},
\code{\link{passwordInput}()},
\code{\link{radioButtons}()},
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}
Other input elements: \code{\link{actionButton}},
\code{\link{checkboxGroupInput}},
\code{\link{checkboxInput}}, \code{\link{dateInput}},
\code{\link{dateRangeInput}}, \code{\link{numericInput}},
\code{\link{passwordInput}}, \code{\link{radioButtons}},
\code{\link{selectInput}}, \code{\link{sliderInput}},
\code{\link{submitButton}}, \code{\link{textAreaInput}},
\code{\link{textInput}}, \code{\link{varSelectInput}}
}
\concept{input elements}

View File

@@ -4,7 +4,8 @@
\alias{fillPage}
\title{Create a page that fills the window}
\usage{
fillPage(..., padding = 0, title = NULL, bootstrap = TRUE, theme = NULL)
fillPage(..., padding = 0, title = NULL, bootstrap = TRUE,
theme = NULL)
}
\arguments{
\item{...}{Elements to include within the page.}
@@ -41,11 +42,11 @@ to the size of the window.
For example, \code{fluidPage(plotOutput("plot", height = "100\%"))} will not
work as expected; the plot element's effective height will be \code{0},
because the plot's containing elements (\verb{<div>} and \verb{<body>}) have
because the plot's containing elements (\code{<div>} and \code{<body>}) have
\emph{automatic} height; that is, they determine their own height based on
the height of their contained elements. However,
\code{fillPage(plotOutput("plot", height = "100\%"))} will work because
\code{fillPage} fixes the \verb{<body>} height at 100\% of the window height.
\code{fillPage} fixes the \code{<body>} height at 100\% of the window height.
Note that \code{fillPage(plotOutput("plot"))} will not cause the plot to fill
the page. Like most Shiny output widgets, \code{plotOutput}'s default height
@@ -82,13 +83,9 @@ fillPage(
)
}
\seealso{
Other layout functions:
\code{\link{fixedPage}()},
\code{\link{flowLayout}()},
\code{\link{fluidPage}()},
\code{\link{navbarPage}()},
\code{\link{sidebarLayout}()},
\code{\link{splitLayout}()},
\code{\link{verticalLayout}()}
Other layout functions: \code{\link{fixedPage}},
\code{\link{flowLayout}}, \code{\link{fluidPage}},
\code{\link{navbarPage}}, \code{\link{sidebarLayout}},
\code{\link{splitLayout}}, \code{\link{verticalLayout}}
}
\concept{layout functions}

View File

@@ -67,13 +67,9 @@ shinyApp(ui, server = function(input, output) { })
\seealso{
\code{\link[=column]{column()}}
Other layout functions:
\code{\link{fillPage}()},
\code{\link{flowLayout}()},
\code{\link{fluidPage}()},
\code{\link{navbarPage}()},
\code{\link{sidebarLayout}()},
\code{\link{splitLayout}()},
\code{\link{verticalLayout}()}
Other layout functions: \code{\link{fillPage}},
\code{\link{flowLayout}}, \code{\link{fluidPage}},
\code{\link{navbarPage}}, \code{\link{sidebarLayout}},
\code{\link{splitLayout}}, \code{\link{verticalLayout}}
}
\concept{layout functions}

View File

@@ -32,13 +32,9 @@ shinyApp(ui, server = function(input, output) { })
}
}
\seealso{
Other layout functions:
\code{\link{fillPage}()},
\code{\link{fixedPage}()},
\code{\link{fluidPage}()},
\code{\link{navbarPage}()},
\code{\link{sidebarLayout}()},
\code{\link{splitLayout}()},
\code{\link{verticalLayout}()}
Other layout functions: \code{\link{fillPage}},
\code{\link{fixedPage}}, \code{\link{fluidPage}},
\code{\link{navbarPage}}, \code{\link{sidebarLayout}},
\code{\link{splitLayout}}, \code{\link{verticalLayout}}
}
\concept{layout functions}

View File

@@ -101,13 +101,9 @@ shinyApp(ui, server = function(input, output) { })
\seealso{
\code{\link[=column]{column()}}
Other layout functions:
\code{\link{fillPage}()},
\code{\link{fixedPage}()},
\code{\link{flowLayout}()},
\code{\link{navbarPage}()},
\code{\link{sidebarLayout}()},
\code{\link{splitLayout}()},
\code{\link{verticalLayout}()}
Other layout functions: \code{\link{fillPage}},
\code{\link{fixedPage}}, \code{\link{flowLayout}},
\code{\link{navbarPage}}, \code{\link{sidebarLayout}},
\code{\link{splitLayout}}, \code{\link{verticalLayout}}
}
\concept{layout functions}

View File

@@ -9,11 +9,6 @@ getCurrentOutputInfo(session = getDefaultReactiveDomain())
\arguments{
\item{session}{The current Shiny session.}
}
\value{
A list with information about the current output, including the
\code{name} of the output. If no output is currently being executed, this will
return \code{NULL}.
}
\description{
Get information about the output that is currently being executed.
}

View File

@@ -15,7 +15,7 @@ getUrlHash(session = getDefaultReactiveDomain())
\value{
For \code{getQueryString}, a named list. For example, the query
string \code{?param1=value1&param2=value2} becomes \code{list(param1 = value1, param2 = value2)}. For \code{getUrlHash}, a character vector with
the hash (including the leading \verb{#} symbol).
the hash (including the leading \code{#} symbol).
}
\description{
Two user friendly wrappers for getting the query string and the hash
@@ -27,7 +27,7 @@ depending on the values in the query string / hash (e.g. instead of basing
the conditional on an input or a calculated reactive, you can base it on the
query string). However, note that, if you're changing the query string / hash
programatically from within the server code, you must use
\verb{updateQueryString(_yourNewQueryString_, mode = "push")}. The default
\code{updateQueryString(_yourNewQueryString_, mode = "push")}. The default
\code{mode} for \code{updateQueryString} is \code{"replace"}, which doesn't
raise any events, so any observers or reactives that depend on it will
\emph{not} get triggered. However, if you're changing the query string / hash
@@ -58,7 +58,7 @@ if (interactive()) {
query <- getQueryString()
queryText <- paste(names(query), query,
sep = "=", collapse=", ")
paste("Your query string is:\n", queryText)
paste("Your query string is:\\n", queryText)
})
}
)
@@ -81,7 +81,7 @@ if (interactive()) {
})
output$hash <- renderText({
hash <- getUrlHash()
paste("Your hash is:\n", hash)
paste("Your hash is:\\n", hash)
})
}
)

View File

@@ -4,13 +4,8 @@
\alias{hoverOpts}
\title{Create an object representing hover options}
\usage{
hoverOpts(
id = NULL,
delay = 300,
delayType = c("debounce", "throttle"),
clip = TRUE,
nullOutside = TRUE
)
hoverOpts(id = NULL, delay = 300, delayType = c("debounce",
"throttle"), clip = TRUE, nullOutside = TRUE)
}
\arguments{
\item{id}{Input value name. For example, if the value is \code{"plot_hover"},

View File

@@ -5,14 +5,11 @@
\alias{uiOutput}
\title{Create an HTML output element}
\usage{
htmlOutput(
outputId,
inline = FALSE,
container = if (inline) span else div,
...
)
htmlOutput(outputId, inline = FALSE, container = if (inline) span else
div, ...)
uiOutput(outputId, inline = FALSE, container = if (inline) span else div, ...)
uiOutput(outputId, inline = FALSE, container = if (inline) span else
div, ...)
}
\arguments{
\item{outputId}{output variable to read the value from}

View File

@@ -7,30 +7,14 @@
\alias{removeTab}
\title{Dynamically insert/remove a tabPanel}
\usage{
insertTab(
inputId,
tab,
target,
position = c("before", "after"),
select = FALSE,
session = getDefaultReactiveDomain()
)
insertTab(inputId, tab, target, position = c("before", "after"),
select = FALSE, session = getDefaultReactiveDomain())
prependTab(
inputId,
tab,
select = FALSE,
menuName = NULL,
session = getDefaultReactiveDomain()
)
prependTab(inputId, tab, select = FALSE, menuName = NULL,
session = getDefaultReactiveDomain())
appendTab(
inputId,
tab,
select = FALSE,
menuName = NULL,
session = getDefaultReactiveDomain()
)
appendTab(inputId, tab, select = FALSE, menuName = NULL,
session = getDefaultReactiveDomain())
removeTab(inputId, target, session = getDefaultReactiveDomain())
}

View File

@@ -2,36 +2,17 @@
% Please edit documentation in R/insert-ui.R
\name{insertUI}
\alias{insertUI}
\alias{removeUI}
\title{Insert and remove UI objects}
\title{Insert UI objects}
\usage{
insertUI(
selector,
where = c("beforeBegin", "afterBegin", "beforeEnd", "afterEnd"),
ui,
multiple = FALSE,
immediate = FALSE,
session = getDefaultReactiveDomain()
)
removeUI(
selector,
multiple = FALSE,
immediate = FALSE,
session = getDefaultReactiveDomain()
)
insertUI(selector, where = c("beforeBegin", "afterBegin", "beforeEnd",
"afterEnd"), ui, multiple = FALSE, immediate = FALSE,
session = getDefaultReactiveDomain())
}
\arguments{
\item{selector}{A string that is accepted by jQuery's selector
(i.e. the string \code{s} to be placed in a \verb{$(s)} jQuery call).
For \code{insertUI()} this determines the element(s) relative to which you
want to insert your UI object. For \code{removeUI()} this determine the
element(s) to be removed. If you want to remove a Shiny input or output,
note that many of these are wrapped in \verb{<div>}s, so you may need to use a
somewhat complex selector --- see the Examples below. (Alternatively, you
could also wrap the inputs/outputs that you want to be able to remove
easily in a \verb{<div>} with an id.)}
\item{selector}{A string that is accepted by jQuery's selector (i.e. the
string \code{s} to be placed in a \code{$(s)} jQuery call). This selector
will determine the element(s) relative to which you want to insert your
UI object.}
\item{where}{Where your UI object should go relative to the selector:
\describe{
@@ -42,7 +23,8 @@ first child}
last child (default)}
\item{\code{afterEnd}}{After the selector element itself}
}
Adapted from \url{https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML}.}
Adapted from
\href{https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML}{here}.}
\item{ui}{The UI object you want to insert. This can be anything that
you usually put inside your apps's \code{ui} function. If you're inserting
@@ -57,27 +39,25 @@ reference or remove it later on). If you want to insert raw html, use
relative to all matched elements or just relative to the first
matched element (default).}
\item{immediate}{Whether the UI object should be immediately inserted
or removed, or whether Shiny should wait until all outputs have been
updated and all observers have been run (default).}
\item{immediate}{Whether the UI object should be immediately inserted into
the app when you call \code{insertUI}, or whether Shiny should wait until
all outputs have been updated and all observers have been run (default).}
\item{session}{The shiny session. Advanced use only.}
\item{session}{The shiny session within which to call \code{insertUI}.}
}
\description{
These functions allow you to dynamically add and remove arbirary UI
into your app, whenever you want, as many times as you want.
Unlike \code{\link[=renderUI]{renderUI()}}, the UI generated with \code{insertUI()} is persistent:
once it's created, it stays there until removed by \code{removeUI()}. Each
new call to \code{insertUI()} creates more UI objects, in addition to
Insert a UI object into the app.
}
\details{
This function allows you to dynamically add an arbitrarily large UI
object into your app, whenever you want, as many times as you want.
Unlike \code{\link[=renderUI]{renderUI()}}, the UI generated with \code{insertUI}
is not updatable as a whole: once it's created, it stays there. Each
new call to \code{insertUI} creates more UI objects, in addition to
the ones already there (all independent from one another). To
update a part of the UI (ex: an input object), you must use the
appropriate \code{render} function or a customized \code{reactive}
function.
}
\details{
It's particularly useful to pair \code{removeUI} with \code{insertUI()}, but there is
no restriction on what you can use on. Any element that can be selected
through a jQuery selector can be removed through this function.
function. To remove any part of your UI, use \code{\link[=removeUI]{removeUI()}}.
}
\examples{
## Only run this example in interactive R sessions
@@ -102,24 +82,7 @@ server <- function(input, output, session) {
# Complete app with UI and server components
shinyApp(ui, server)
}
if (interactive()) {
# Define UI
ui <- fluidPage(
actionButton("rmv", "Remove UI"),
textInput("txt", "This is no longer useful")
)
# Server logic
server <- function(input, output, session) {
observeEvent(input$rmv, {
removeUI(
selector = "div:has(> #txt)"
)
})
}
# Complete app with UI and server components
shinyApp(ui, server)
}
\seealso{
\code{\link[=removeUI]{removeUI()}}
}

View File

@@ -4,16 +4,10 @@
\alias{installExprFunction}
\title{Install an expression as a function}
\usage{
installExprFunction(
expr,
name,
eval.env = parent.frame(2),
quoted = FALSE,
assign.env = parent.frame(1),
label = deparse(sys.call(-1)[[1]]),
wrappedWithLabel = TRUE,
..stacktraceon = FALSE
)
installExprFunction(expr, name, eval.env = parent.frame(2),
quoted = FALSE, assign.env = parent.frame(1),
label = deparse(sys.call(-1)[[1]]), wrappedWithLabel = TRUE,
..stacktraceon = FALSE)
}
\arguments{
\item{expr}{A quoted or unquoted expression}

View File

@@ -4,16 +4,13 @@
\alias{loadSupport}
\title{Load an app's supporting R files}
\usage{
loadSupport(
appDir,
renv = new.env(parent = globalenv()),
globalrenv = globalenv()
)
loadSupport(appDir, renv = new.env(parent = globalenv()),
globalrenv = globalenv())
}
\arguments{
\item{appDir}{The application directory}
\item{renv}{The environmeny in which the files in the \verb{R/} directory should
\item{renv}{The environmeny in which the files in the \code{R/} directory should
be evaluated.}
\item{globalrenv}{The environment in which \code{global.R} should be evaluated. If
@@ -21,19 +18,19 @@ be evaluated.}
}
\description{
Loads all of the supporting R files of a Shiny application. Specifically,
this function loads any top-level supporting \code{.R} files in the \verb{R/} directory
this function loads any top-level supporting \code{.R} files in the \code{R/} directory
adjacent to the \code{app.R}/\code{server.R}/\code{ui.R} files.
}
\details{
Since Shiny 1.5.0, this function is called by default when running an
application. If it causes problems, there are two ways to opt out. You can
either place a file named \verb{_disable_autoload.R} in your R/ directory, or
set \code{options(shiny.autoload.r=FALSE)}. If you set this option, it will
application. If it causes problems, you can opt out by using
\code{options(shiny.autoload.r=FALSE)}. Note that in a future version of Shiny,
this option will no longer be available. If you set this option, it will
affect any application that runs later in the same R session, potentially
breaking it, so after running your application, you should unset option with
\code{options(shiny.autoload.r=NULL)}
The files are sourced in alphabetical order (as determined by
\link{list.files}). \code{global.R} is evaluated before the supporting R files in the
\verb{R/} directory.
\code{R/} directory.
}

View File

@@ -4,7 +4,8 @@
\alias{markOutputAttrs}
\title{Mark a render function with attributes that will be used by the output}
\usage{
markOutputAttrs(renderFunc, snapshotExclude = NULL, snapshotPreprocess = NULL)
markOutputAttrs(renderFunc, snapshotExclude = NULL,
snapshotPreprocess = NULL)
}
\arguments{
\item{renderFunc}{A function that is suitable for assigning to a Shiny output

View File

@@ -4,15 +4,9 @@
\alias{memoryCache}
\title{Create a memory cache object}
\usage{
memoryCache(
max_size = 10 * 1024^2,
max_age = Inf,
max_n = Inf,
evict = c("lru", "fifo"),
missing = key_missing(),
exec_missing = FALSE,
logfile = NULL
)
memoryCache(max_size = 10 * 1024^2, max_age = Inf, max_n = Inf,
evict = c("lru", "fifo"), missing = key_missing(),
exec_missing = FALSE, logfile = NULL)
}
\arguments{
\item{max_size}{Maximum size of the cache, in bytes. If the cache exceeds

View File

@@ -4,14 +4,8 @@
\alias{modalDialog}
\title{Create a modal dialog UI}
\usage{
modalDialog(
...,
title = NULL,
footer = modalButton("Dismiss"),
size = c("m", "s", "l"),
easyClose = FALSE,
fade = TRUE
)
modalDialog(..., title = NULL, footer = modalButton("Dismiss"),
size = c("m", "s", "l"), easyClose = FALSE, fade = TRUE)
}
\arguments{
\item{...}{UI elements for the body of the modal dialog box.}

View File

@@ -1,101 +0,0 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/modules.R
\name{moduleServer}
\alias{moduleServer}
\alias{callModule}
\title{Shiny modules}
\usage{
moduleServer(id, module, session = getDefaultReactiveDomain())
callModule(module, id, ..., session = getDefaultReactiveDomain())
}
\arguments{
\item{id}{An ID string that corresponds with the ID used to call the module's
UI function.}
\item{module}{A Shiny module server function.}
\item{session}{Session from which to make a child scope (the default should
almost always be used).}
\item{...}{For \code{callModule}, additional parameters to pass to module server
function.}
}
\value{
The return value, if any, from executing the module server function
}
\description{
Shiny's module feature lets you break complicated UI and server logic into
smaller, self-contained pieces. Compared to large monolithic Shiny apps,
modules are easier to reuse and easier to reason about. See the article at
\url{http://shiny.rstudio.com/articles/modules.html} to learn more.
}
\details{
Starting in Shiny 1.5.0, we recommend using \code{moduleFunction} instead of
\code{callModule}, because syntax is a little easier to understand.
}
\examples{
# Define the UI for a module
counterUI <- function(id, label = "Counter") {
ns <- NS(id)
tagList(
actionButton(ns("button"), label = label),
verbatimTextOutput(ns("out"))
)
}
# Define the server logic for a module
counterServer <- function(id) {
moduleServer(id, function(input, output, session) {
count <- reactiveVal(0)
observeEvent(input$button, {
count(count() + 1)
})
output$out <- renderText({
count()
})
count
})
}
# Use the module in an app
ui <- fluidPage(
counterUI("counter1", "Counter #1"),
counterUI("counter2", "Counter #2")
)
server <- function(input, output, session) {
counterServer("counter1")
counterServer("counter2")
}
shinyApp(ui, server)
# If you want to pass extra parameters to the module's server logic, you can
# add them to your function. In this case `prefix` is text that will be
# printed before the count.
counterServer2 <- function(id, prefix = NULL) {
moduleServer(id, function(input, output, session) {
count <- reactiveVal(0)
observeEvent(input$button, {
count(count() + 1)
})
output$out <- renderText({
paste0(prefix, count())
})
count
})
}
ui <- fluidPage(
counterUI("counter", "Counter"),
)
server <- function(input, output, session) {
counterServer2("counter", "The current count is: ")
}
shinyApp(ui, server)
}
\seealso{
\url{http://shiny.rstudio.com/articles/modules.html}
}

View File

@@ -5,22 +5,11 @@
\alias{navbarMenu}
\title{Create a page with a top level navigation bar}
\usage{
navbarPage(
title,
...,
id = NULL,
selected = NULL,
navbarPage(title, ..., id = NULL, selected = NULL,
position = c("static-top", "fixed-top", "fixed-bottom"),
header = NULL,
footer = NULL,
inverse = FALSE,
collapsible = FALSE,
collapsable,
fluid = TRUE,
responsive = NULL,
theme = NULL,
windowTitle = title
)
header = NULL, footer = NULL, inverse = FALSE,
collapsible = FALSE, collapsable, fluid = TRUE, responsive = NULL,
theme = NULL, windowTitle = title)
navbarMenu(title, ..., menuName = title, icon = NULL)
}
@@ -32,7 +21,7 @@ navbarMenu(title, ..., menuName = title, icon = NULL)
section headers. If the string is a set of dashes like \code{"----"} a
horizontal separator will be displayed in the menu.}
\item{id}{If provided, you can use \verb{input$}\emph{\code{id}} in your
\item{id}{If provided, you can use \code{input$}\emph{\code{id}} in your
server logic to determine which of the current tabs is active. The value
will correspond to the \code{value} argument that is passed to
\code{\link[=tabPanel]{tabPanel()}}.}
@@ -117,13 +106,9 @@ navbarPage("App Title",
\code{\link[=updateNavbarPage]{updateNavbarPage()}}, \code{\link[=insertTab]{insertTab()}},
\code{\link[=showTab]{showTab()}}
Other layout functions:
\code{\link{fillPage}()},
\code{\link{fixedPage}()},
\code{\link{flowLayout}()},
\code{\link{fluidPage}()},
\code{\link{sidebarLayout}()},
\code{\link{splitLayout}()},
\code{\link{verticalLayout}()}
Other layout functions: \code{\link{fillPage}},
\code{\link{fixedPage}}, \code{\link{flowLayout}},
\code{\link{fluidPage}}, \code{\link{sidebarLayout}},
\code{\link{splitLayout}}, \code{\link{verticalLayout}}
}
\concept{layout functions}

View File

@@ -4,19 +4,13 @@
\alias{navlistPanel}
\title{Create a navigation list panel}
\usage{
navlistPanel(
...,
id = NULL,
selected = NULL,
well = TRUE,
fluid = TRUE,
widths = c(4, 8)
)
navlistPanel(..., id = NULL, selected = NULL, well = TRUE,
fluid = TRUE, widths = c(4, 8))
}
\arguments{
\item{...}{\code{\link[=tabPanel]{tabPanel()}} elements to include in the navlist}
\item{id}{If provided, you can use \verb{input$}\emph{\code{id}} in your
\item{id}{If provided, you can use \code{input$}\emph{\code{id}} in your
server logic to determine which of the current navlist items is active. The
value will correspond to the \code{value} argument that is passed to
\code{\link[=tabPanel]{tabPanel()}}.}

View File

@@ -4,18 +4,9 @@
\alias{nearPoints}
\title{Find rows of data that are near a click/hover/double-click}
\usage{
nearPoints(
df,
coordinfo,
xvar = NULL,
yvar = NULL,
panelvar1 = NULL,
panelvar2 = NULL,
threshold = 5,
maxpoints = NULL,
addDist = FALSE,
allRows = FALSE
)
nearPoints(df, coordinfo, xvar = NULL, yvar = NULL, panelvar1 = NULL,
panelvar2 = NULL, threshold = 5, maxpoints = NULL,
addDist = FALSE, allRows = FALSE)
}
\arguments{
\item{df}{A data frame from which to select rows.}

View File

@@ -4,15 +4,8 @@
\alias{numericInput}
\title{Create a numeric input control}
\usage{
numericInput(
inputId,
label,
value,
min = NA,
max = NA,
step = NA,
width = NULL
)
numericInput(inputId, label, value, min = NA, max = NA, step = NA,
width = NULL)
}
\arguments{
\item{inputId}{The \code{input} slot that will be used to access the value.}
@@ -59,20 +52,13 @@ shinyApp(ui, server)
\seealso{
\code{\link[=updateNumericInput]{updateNumericInput()}}
Other input elements:
\code{\link{actionButton}()},
\code{\link{checkboxGroupInput}()},
\code{\link{checkboxInput}()},
\code{\link{dateInput}()},
\code{\link{dateRangeInput}()},
\code{\link{fileInput}()},
\code{\link{passwordInput}()},
\code{\link{radioButtons}()},
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}
Other input elements: \code{\link{actionButton}},
\code{\link{checkboxGroupInput}},
\code{\link{checkboxInput}}, \code{\link{dateInput}},
\code{\link{dateRangeInput}}, \code{\link{fileInput}},
\code{\link{passwordInput}}, \code{\link{radioButtons}},
\code{\link{selectInput}}, \code{\link{sliderInput}},
\code{\link{submitButton}}, \code{\link{textAreaInput}},
\code{\link{textInput}}, \code{\link{varSelectInput}}
}
\concept{input elements}

View File

@@ -4,17 +4,10 @@
\alias{observe}
\title{Create a reactive observer}
\usage{
observe(
x,
env = parent.frame(),
quoted = FALSE,
label = NULL,
suspended = FALSE,
priority = 0,
domain = getDefaultReactiveDomain(),
autoDestroy = TRUE,
..stacktraceon = TRUE
)
observe(x, env = parent.frame(), quoted = FALSE, label = NULL,
suspended = FALSE, priority = 0,
domain = getDefaultReactiveDomain(), autoDestroy = TRUE,
..stacktraceon = TRUE)
}
\arguments{
\item{x}{An expression (quoted or unquoted). Any return value will be

View File

@@ -5,35 +5,18 @@
\alias{eventReactive}
\title{Event handler}
\usage{
observeEvent(
eventExpr,
handlerExpr,
event.env = parent.frame(),
event.quoted = FALSE,
handler.env = parent.frame(),
handler.quoted = FALSE,
label = NULL,
suspended = FALSE,
priority = 0,
domain = getDefaultReactiveDomain(),
autoDestroy = TRUE,
ignoreNULL = TRUE,
ignoreInit = FALSE,
once = FALSE
)
observeEvent(eventExpr, handlerExpr, event.env = parent.frame(),
event.quoted = FALSE, handler.env = parent.frame(),
handler.quoted = FALSE, label = NULL, suspended = FALSE,
priority = 0, domain = getDefaultReactiveDomain(),
autoDestroy = TRUE, ignoreNULL = TRUE, ignoreInit = FALSE,
once = FALSE)
eventReactive(
eventExpr,
valueExpr,
event.env = parent.frame(),
event.quoted = FALSE,
value.env = parent.frame(),
value.quoted = FALSE,
label = NULL,
domain = getDefaultReactiveDomain(),
ignoreNULL = TRUE,
ignoreInit = FALSE
)
eventReactive(eventExpr, valueExpr, event.env = parent.frame(),
event.quoted = FALSE, value.env = parent.frame(),
value.quoted = FALSE, label = NULL,
domain = getDefaultReactiveDomain(), ignoreNULL = TRUE,
ignoreInit = FALSE)
}
\arguments{
\item{eventExpr}{A (quoted or unquoted) expression that represents the event;
@@ -165,7 +148,7 @@ button, then \code{ignoreInit = TRUE} will guarantee that the action (in
instead of also being triggered when it is created/initialized. Similarly,
if you're setting up an \code{eventReactive} that responds to a dynamically
created button used to refresh some data (then returned by that \code{eventReactive}),
then you should use \verb{eventReactive([...], ignoreInit = TRUE)} if you want
then you should use \code{eventReactive([...], ignoreInit = TRUE)} if you want
to let the user decide if/when they want to refresh the data (since, depending
on the app, this may be a computationally expensive operation).
@@ -219,7 +202,7 @@ if (interactive()) {
# Take an action every time button is pressed;
# here, we just print a message to the console
observeEvent(input$button, {
cat("Showing", input$x, "rows\n")
cat("Showing", input$x, "rows\\n")
})
# Take a reactive dependency on input$button, but
# not on any of the stuff inside the function

View File

@@ -92,14 +92,14 @@ ui <- function(req) {
server <- function(input, output) {
onBookmark(function(state) {
savedTime <- as.character(Sys.time())
cat("Last saved at", savedTime, "\n")
cat("Last saved at", savedTime, "\\n")
# state is a mutable reference object, and we can add arbitrary values to
# it.
state$values$time <- savedTime
})
onRestore(function(state) {
cat("Restoring from state bookmarked at", state$values$time, "\n")
cat("Restoring from state bookmarked at", state$values$time, "\\n")
})
}
enableBookmarking("url")

View File

@@ -33,14 +33,14 @@ if (interactive()) {
ui = basicPage("onStop demo"),
server = function(input, output, session) {
onStop(function() cat("Session stopped\n"))
onStop(function() cat("Session stopped\\n"))
},
onStart = function() {
cat("Doing application setup\n")
cat("Doing application setup\\n")
onStop(function() {
cat("Doing application cleanup\n")
cat("Doing application cleanup\\n")
})
}
)
@@ -53,16 +53,16 @@ if (interactive()) {
\dontrun{
# ==== app.R ====
cat("Doing application setup\n")
cat("Doing application setup\\n")
onStop(function() {
cat("Doing application cleanup\n")
cat("Doing application cleanup\\n")
})
shinyApp(
ui = basicPage("onStop demo"),
server = function(input, output, session) {
onStop(function() cat("Session stopped\n"))
onStop(function() cat("Session stopped\\n"))
}
)
# ==== end app.R ====
@@ -70,9 +70,9 @@ shinyApp(
# Similarly, if you have a global.R, you can call onStop() from there.
# ==== global.R ====
cat("Doing application setup\n")
cat("Doing application setup\\n")
onStop(function() {
cat("Doing application cleanup\n")
cat("Doing application cleanup\\n")
})
# ==== end global.R ====
}

View File

@@ -4,7 +4,8 @@
\alias{passwordInput}
\title{Create a password input control}
\usage{
passwordInput(inputId, label, value = "", width = NULL, placeholder = NULL)
passwordInput(inputId, label, value = "", width = NULL,
placeholder = NULL)
}
\arguments{
\item{inputId}{The \code{input} slot that will be used to access the value.}
@@ -53,20 +54,13 @@ shinyApp(ui, server)
\seealso{
\code{\link[=updateTextInput]{updateTextInput()}}
Other input elements:
\code{\link{actionButton}()},
\code{\link{checkboxGroupInput}()},
\code{\link{checkboxInput}()},
\code{\link{dateInput}()},
\code{\link{dateRangeInput}()},
\code{\link{fileInput}()},
\code{\link{numericInput}()},
\code{\link{radioButtons}()},
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}
Other input elements: \code{\link{actionButton}},
\code{\link{checkboxGroupInput}},
\code{\link{checkboxInput}}, \code{\link{dateInput}},
\code{\link{dateRangeInput}}, \code{\link{fileInput}},
\code{\link{numericInput}}, \code{\link{radioButtons}},
\code{\link{selectInput}}, \code{\link{sliderInput}},
\code{\link{submitButton}}, \code{\link{textAreaInput}},
\code{\link{textInput}}, \code{\link{varSelectInput}}
}
\concept{input elements}

View File

@@ -5,35 +5,15 @@
\alias{imageOutput}
\title{Create an plot or image output element}
\usage{
imageOutput(
outputId,
width = "100\%",
height = "400px",
click = NULL,
dblclick = NULL,
hover = NULL,
hoverDelay = NULL,
hoverDelayType = NULL,
brush = NULL,
clickId = NULL,
hoverId = NULL,
inline = FALSE
)
imageOutput(outputId, width = "100\%", height = "400px",
click = NULL, dblclick = NULL, hover = NULL, hoverDelay = NULL,
hoverDelayType = NULL, brush = NULL, clickId = NULL,
hoverId = NULL, inline = FALSE)
plotOutput(
outputId,
width = "100\%",
height = "400px",
click = NULL,
dblclick = NULL,
hover = NULL,
hoverDelay = NULL,
hoverDelayType = NULL,
brush = NULL,
clickId = NULL,
hoverId = NULL,
inline = FALSE
)
plotOutput(outputId, width = "100\%", height = "400px", click = NULL,
dblclick = NULL, hover = NULL, hoverDelay = NULL,
hoverDelayType = NULL, brush = NULL, clickId = NULL,
hoverId = NULL, inline = FALSE)
}
\arguments{
\item{outputId}{output variable to read the plot/image from.}
@@ -115,7 +95,7 @@ not work for \pkg{\link[grid:grid-package]{grid}}-based graphics, such as
Plots and images in Shiny support mouse-based interaction, via clicking,
double-clicking, hovering, and brushing. When these interaction events
occur, the mouse coordinates will be sent to the server as \verb{input$}
occur, the mouse coordinates will be sent to the server as \code{input$}
variables, as specified by \code{click}, \code{dblclick}, \code{hover}, or
\code{brush}.
@@ -195,15 +175,15 @@ shinyApp(
plot(d$speed, d$dist)
})
output$plot_clickinfo <- renderPrint({
cat("Click:\n")
cat("Click:\\n")
str(input$plot_click)
})
output$plot_hoverinfo <- renderPrint({
cat("Hover (throttled):\n")
cat("Hover (throttled):\\n")
str(input$plot_hover)
})
output$plot_brushinfo <- renderPrint({
cat("Brush (debounced):\n")
cat("Brush (debounced):\\n")
str(input$plot_brush)
})
output$plot_clickedpoints <- renderTable({
@@ -275,15 +255,15 @@ shinyApp(
)
})
output$image_clickinfo <- renderPrint({
cat("Click:\n")
cat("Click:\\n")
str(input$image_click)
})
output$image_hoverinfo <- renderPrint({
cat("Hover (throttled):\n")
cat("Hover (throttled):\\n")
str(input$image_hover)
})
output$image_brushinfo <- renderPrint({
cat("Brush (debounced):\n")
cat("Brush (debounced):\\n")
str(input$image_brush)
})
}

View File

@@ -4,14 +4,8 @@
\alias{plotPNG}
\title{Run a plotting function and save the output as a PNG}
\usage{
plotPNG(
func,
filename = tempfile(fileext = ".png"),
width = 400,
height = 400,
res = 72,
...
)
plotPNG(func, filename = tempfile(fileext = ".png"), width = 400,
height = 400, res = 72, ...)
}
\arguments{
\item{func}{A function that generates a plot.}

View File

@@ -4,16 +4,9 @@
\alias{radioButtons}
\title{Create radio buttons}
\usage{
radioButtons(
inputId,
label,
choices = NULL,
selected = NULL,
inline = FALSE,
width = NULL,
choiceNames = NULL,
choiceValues = NULL
)
radioButtons(inputId, label, choices = NULL, selected = NULL,
inline = FALSE, width = NULL, choiceNames = NULL,
choiceValues = NULL)
}
\arguments{
\item{inputId}{The \code{input} slot that will be used to access the value.}
@@ -115,20 +108,13 @@ shinyApp(ui, server)
\seealso{
\code{\link[=updateRadioButtons]{updateRadioButtons()}}
Other input elements:
\code{\link{actionButton}()},
\code{\link{checkboxGroupInput}()},
\code{\link{checkboxInput}()},
\code{\link{dateInput}()},
\code{\link{dateRangeInput}()},
\code{\link{fileInput}()},
\code{\link{numericInput}()},
\code{\link{passwordInput}()},
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}
Other input elements: \code{\link{actionButton}},
\code{\link{checkboxGroupInput}},
\code{\link{checkboxInput}}, \code{\link{dateInput}},
\code{\link{dateRangeInput}}, \code{\link{fileInput}},
\code{\link{numericInput}}, \code{\link{passwordInput}},
\code{\link{selectInput}}, \code{\link{sliderInput}},
\code{\link{submitButton}}, \code{\link{textAreaInput}},
\code{\link{textInput}}, \code{\link{varSelectInput}}
}
\concept{input elements}

View File

@@ -5,14 +5,8 @@
\alias{is.reactive}
\title{Create a reactive expression}
\usage{
reactive(
x,
env = parent.frame(),
quoted = FALSE,
label = NULL,
domain = getDefaultReactiveDomain(),
..stacktraceon = TRUE
)
reactive(x, env = parent.frame(), quoted = FALSE, label = NULL,
domain = getDefaultReactiveDomain(), ..stacktraceon = TRUE)
is.reactive(x)
}

View File

@@ -49,8 +49,8 @@ last modified timestamp of a file, and a value retrieval function that
actually reads the contents of the file.
As another example, one might read a relational database table reactively by
using a check function that does \verb{SELECT MAX(timestamp) FROM table} and
a value retrieval function that does \verb{SELECT * FROM table}.
using a check function that does \code{SELECT MAX(timestamp) FROM table} and
a value retrieval function that does \code{SELECT * FROM table}.
The \code{intervalMillis}, \code{checkFunc}, and \code{valueFunc} functions
will be executed in a reactive context; therefore, they may read reactive

View File

@@ -12,6 +12,6 @@ These objects are imported from other packages. Follow the links
below to see their documentation.
\describe{
\item{fastmap}{\code{\link[fastmap]{is.key_missing}}, \code{\link[fastmap]{key_missing}}}
\item{fastmap}{\code{\link[fastmap]{key_missing}}, \code{\link[fastmap]{is.key_missing}}}
}}

66
man/removeUI.Rd Normal file
View File

@@ -0,0 +1,66 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/insert-ui.R
\name{removeUI}
\alias{removeUI}
\title{Remove UI objects}
\usage{
removeUI(selector, multiple = FALSE, immediate = FALSE,
session = getDefaultReactiveDomain())
}
\arguments{
\item{selector}{A string that is accepted by jQuery's selector (i.e. the
string \code{s} to be placed in a \code{$(s)} jQuery call). This selector
will determine the element(s) to be removed. If you want to remove a
Shiny input or output, note that many of these are wrapped in \code{div}s,
so you may need to use a somewhat complex selector --- see the Examples below.
(Alternatively, you could also wrap the inputs/outputs that you want to be
able to remove easily in a \code{div} with an id.)}
\item{multiple}{In case your selector matches more than one element,
\code{multiple} determines whether Shiny should remove all the matched
elements or just the first matched element (default).}
\item{immediate}{Whether the element(s) should be immediately removed from
the app when you call \code{removeUI}, or whether Shiny should wait until
all outputs have been updated and all observers have been run (default).}
\item{session}{The shiny session within which to call \code{removeUI}.}
}
\description{
Remove a UI object from the app.
}
\details{
This function allows you to remove any part of your UI. Once \code{removeUI}
is executed on some element, it is gone forever.
While it may be a particularly useful pattern to pair this with
\code{\link[=insertUI]{insertUI()}} (to remove some UI you had previously inserted),
there is no restriction on what you can use \code{removeUI} on. Any
element that can be selected through a jQuery selector can be removed
through this function.
}
\examples{
## Only run this example in interactive R sessions
if (interactive()) {
# Define UI
ui <- fluidPage(
actionButton("rmv", "Remove UI"),
textInput("txt", "This is no longer useful")
)
# Server logic
server <- function(input, output, session) {
observeEvent(input$rmv, {
removeUI(
selector = "div:has(> #txt)"
)
})
}
# Complete app with UI and server components
shinyApp(ui, server)
}
}
\seealso{
\code{\link[=insertUI]{insertUI()}}
}

View File

@@ -4,15 +4,9 @@
\alias{renderCachedPlot}
\title{Plot output with cached images}
\usage{
renderCachedPlot(
expr,
cacheKeyExpr,
sizePolicy = sizeGrowthRatio(width = 400, height = 400, growthRate = 1.2),
res = 72,
cache = "app",
...,
outputArgs = list()
)
renderCachedPlot(expr, cacheKeyExpr, sizePolicy = sizeGrowthRatio(width =
400, height = 400, growthRate = 1.2), res = 72, cache = "app", ...,
outputArgs = list())
}
\arguments{
\item{expr}{An expression that generates a plot.}

View File

@@ -4,16 +4,9 @@
\alias{renderDataTable}
\title{Table output with the JavaScript library DataTables}
\usage{
renderDataTable(
expr,
options = NULL,
searchDelay = 500,
callback = "function(oTable) {}",
escape = TRUE,
env = parent.frame(),
quoted = FALSE,
outputArgs = list()
)
renderDataTable(expr, options = NULL, searchDelay = 500,
callback = "function(oTable) {}", escape = TRUE,
env = parent.frame(), quoted = FALSE, outputArgs = list())
}
\arguments{
\item{expr}{An expression that returns a data frame or a matrix.}

View File

@@ -4,13 +4,8 @@
\alias{renderImage}
\title{Image file output}
\usage{
renderImage(
expr,
env = parent.frame(),
quoted = FALSE,
deleteFile = TRUE,
outputArgs = list()
)
renderImage(expr, env = parent.frame(), quoted = FALSE,
deleteFile = TRUE, outputArgs = list())
}
\arguments{
\item{expr}{An expression that returns a list.}

View File

@@ -4,17 +4,9 @@
\alias{renderPlot}
\title{Plot Output}
\usage{
renderPlot(
expr,
width = "auto",
height = "auto",
res = 72,
...,
env = parent.frame(),
quoted = FALSE,
execOnResize = FALSE,
outputArgs = list()
)
renderPlot(expr, width = "auto", height = "auto", res = 72, ...,
env = parent.frame(), quoted = FALSE, execOnResize = FALSE,
outputArgs = list())
}
\arguments{
\item{expr}{An expression that generates a plot.}

View File

@@ -4,13 +4,8 @@
\alias{renderPrint}
\title{Printable Output}
\usage{
renderPrint(
expr,
env = parent.frame(),
quoted = FALSE,
width = getOption("width"),
outputArgs = list()
)
renderPrint(expr, env = parent.frame(), quoted = FALSE,
width = getOption("width"), outputArgs = list())
}
\arguments{
\item{expr}{An expression that may print output and/or return a printable R
@@ -21,7 +16,7 @@ object.}
\item{quoted}{Is \code{expr} a quoted expression (with \code{quote()})? This
is useful if you want to save an expression in a variable.}
\item{width}{The value for \verb{[options][base::options]('width')}.}
\item{width}{The value for \code{[options][base::options]('width')}.}
\item{outputArgs}{A list of arguments to be passed through to the implicit
call to \code{\link[=verbatimTextOutput]{verbatimTextOutput()}} when \code{renderPrint} is used
@@ -63,7 +58,7 @@ multiprintFun <- renderPrint({
"bar"
})
multiprintFun()
# '[1] "foo"\n[1] "bar"'
# '[1] "foo"\\n[1] "bar"'
nullFun <- renderPrint({ NULL })
nullFun()

View File

@@ -4,23 +4,10 @@
\alias{renderTable}
\title{Table Output}
\usage{
renderTable(
expr,
striped = FALSE,
hover = FALSE,
bordered = FALSE,
spacing = c("s", "xs", "m", "l"),
width = "auto",
align = NULL,
rownames = FALSE,
colnames = TRUE,
digits = NULL,
na = "NA",
...,
env = parent.frame(),
quoted = FALSE,
outputArgs = list()
)
renderTable(expr, striped = FALSE, hover = FALSE, bordered = FALSE,
spacing = c("s", "xs", "m", "l"), width = "auto", align = NULL,
rownames = FALSE, colnames = TRUE, digits = NULL, na = "NA", ...,
env = parent.frame(), quoted = FALSE, outputArgs = list())
}
\arguments{
\item{expr}{An expression that returns an R object that can be used with
@@ -33,7 +20,7 @@ corresponding Bootstrap table format to the output table.}
stands for "extra small", \code{s} for "small", \code{m} for "medium"
and \code{l} for "large").}
\item{width}{Table width. Must be a valid CSS unit (like "100\%", "400px",
\item{width}{Table width. Must be a valid CSS unit (like "100%", "400px",
"auto") or a number, which will be coerced to a string and
have "px" appended.}

View File

@@ -4,13 +4,8 @@
\alias{renderText}
\title{Text Output}
\usage{
renderText(
expr,
env = parent.frame(),
quoted = FALSE,
outputArgs = list(),
sep = " "
)
renderText(expr, env = parent.frame(), quoted = FALSE,
outputArgs = list(), sep = " ")
}
\arguments{
\item{expr}{An expression that returns an R object that can be used as an
@@ -59,7 +54,7 @@ multiprintFun <- renderPrint({
"bar"
})
multiprintFun()
# '[1] "foo"\n[1] "bar"'
# '[1] "foo"\\n[1] "bar"'
nullFun <- renderPrint({ NULL })
nullFun()

View File

@@ -4,7 +4,8 @@
\alias{renderUI}
\title{UI Output}
\usage{
renderUI(expr, env = parent.frame(), quoted = FALSE, outputArgs = list())
renderUI(expr, env = parent.frame(), quoted = FALSE,
outputArgs = list())
}
\arguments{
\item{expr}{An expression that returns a Shiny tag object, \code{\link[=HTML]{HTML()}},

View File

@@ -29,7 +29,7 @@ supporting JavaScript/CSS files available to their components.
\details{
Shiny provides two ways of serving static files (i.e., resources):
\enumerate{
\item Static files under the \verb{www/} directory are automatically made available
\item Static files under the \code{www/} directory are automatically made available
under a request path that begins with \code{/}.
\item \code{addResourcePath()} makes static files in a \code{directoryPath} available
under a request path that begins with \code{prefix}.

View File

@@ -4,16 +4,11 @@
\alias{runApp}
\title{Run Shiny Application}
\usage{
runApp(
appDir = getwd(),
port = getOption("shiny.port"),
runApp(appDir = getwd(), port = getOption("shiny.port"),
launch.browser = getOption("shiny.launch.browser", interactive()),
host = getOption("shiny.host", "127.0.0.1"),
workerId = "",
quiet = FALSE,
display.mode = c("auto", "normal", "showcase"),
test.mode = getOption("shiny.testmode", FALSE)
)
host = getOption("shiny.host", "127.0.0.1"), workerId = "",
quiet = FALSE, display.mode = c("auto", "normal", "showcase"),
test.mode = getOption("shiny.testmode", FALSE))
}
\arguments{
\item{appDir}{The application to run. Should be one of the following:

View File

@@ -4,13 +4,10 @@
\alias{runExample}
\title{Run Shiny Example Applications}
\usage{
runExample(
example = NA,
port = NULL,
runExample(example = NA, port = NULL,
launch.browser = getOption("shiny.launch.browser", interactive()),
host = getOption("shiny.host", "127.0.0.1"),
display.mode = c("auto", "normal", "showcase")
)
host = getOption("shiny.host", "127.0.0.1"), display.mode = c("auto",
"normal", "showcase"))
}
\arguments{
\item{example}{The name of the example to run, or \code{NA} (the default) to

View File

@@ -4,13 +4,8 @@
\alias{runGadget}
\title{Run a gadget}
\usage{
runGadget(
app,
server = NULL,
port = getOption("shiny.port"),
viewer = paneViewer(),
stopOnCancel = TRUE
)
runGadget(app, server = NULL, port = getOption("shiny.port"),
viewer = paneViewer(), stopOnCancel = TRUE)
}
\arguments{
\item{app}{Either a Shiny app object as created by

View File

@@ -1,27 +0,0 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/test.R
\name{runTests}
\alias{runTests}
\title{Runs the tests associated with this Shiny app}
\usage{
runTests(appDir = ".", filter = NULL)
}
\arguments{
\item{appDir}{The base directory for the application.}
\item{filter}{If not \code{NULL}, only tests with file names matching this regular
expression will be executed. Matching is performed on the file name
including the extension.}
}
\description{
Sources the \code{.R} files in the top-level of \verb{tests/} much like \verb{R CMD check}.
These files are typically simple runners for tests nested in other
directories under \verb{tests/}.
}
\details{
Historically, \href{https://rstudio.github.io/shinytest/}{shinytest}
recommended placing tests at the top-level of the \verb{tests/} directory. In
order to support that model, \code{testApp} first checks to see if the \code{.R}
files in the \verb{tests/} directory are all shinytests; if so, just calls out
to \code{\link[shinytest:testApp]{shinytest::testApp()}}.
}

View File

@@ -10,14 +10,8 @@ runUrl(url, filetype = NULL, subdir = NULL, destdir = NULL, ...)
runGist(gist, destdir = NULL, ...)
runGitHub(
repo,
username = getOption("github.user"),
ref = "master",
subdir = NULL,
destdir = NULL,
...
)
runGitHub(repo, username = getOption("github.user"), ref = "master",
subdir = NULL, destdir = NULL, ...)
}
\arguments{
\item{url}{URL of the application.}

View File

@@ -5,16 +5,8 @@
\alias{selectizeInput}
\title{Create a select list input control}
\usage{
selectInput(
inputId,
label,
choices,
selected = NULL,
multiple = FALSE,
selectize = TRUE,
width = NULL,
size = NULL
)
selectInput(inputId, label, choices, selected = NULL, multiple = FALSE,
selectize = TRUE, width = NULL, size = NULL)
selectizeInput(inputId, ..., options = NULL, width = NULL)
}
@@ -28,7 +20,7 @@ named, then that name --- rather than the value --- is displayed to the
user. It's also possible to group related inputs by providing a named list
whose elements are (either named or unnamed) lists, vectors, or factors. In
this case, the outermost names will be used as the group labels (leveraging
the \verb{<optgroup>} HTML tag) for the elements in the respective sublist. See
the \code{<optgroup>} HTML tag) for the elements in the respective sublist. See
the example section for a small demo of this feature.}
\item{selected}{The initially selected value (or multiple values if \code{multiple = TRUE}). If not specified then defaults to the first value for
@@ -128,20 +120,13 @@ shinyApp(
\seealso{
\code{\link[=updateSelectInput]{updateSelectInput()}} \code{\link[=varSelectInput]{varSelectInput()}}
Other input elements:
\code{\link{actionButton}()},
\code{\link{checkboxGroupInput}()},
\code{\link{checkboxInput}()},
\code{\link{dateInput}()},
\code{\link{dateRangeInput}()},
\code{\link{fileInput}()},
\code{\link{numericInput}()},
\code{\link{passwordInput}()},
\code{\link{radioButtons}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}
Other input elements: \code{\link{actionButton}},
\code{\link{checkboxGroupInput}},
\code{\link{checkboxInput}}, \code{\link{dateInput}},
\code{\link{dateRangeInput}}, \code{\link{fileInput}},
\code{\link{numericInput}}, \code{\link{passwordInput}},
\code{\link{radioButtons}}, \code{\link{sliderInput}},
\code{\link{submitButton}}, \code{\link{textAreaInput}},
\code{\link{textInput}}, \code{\link{varSelectInput}}
}
\concept{input elements}

View File

@@ -20,7 +20,7 @@ on a local connection (without Shiny Server or Connect).
A \code{\link[=reactiveValues]{reactiveValues()}} object that contains information about the client.
\itemize{
\item{\code{allowDataUriScheme} is a logical value that indicates whether
the browser is able to handle URIs that use the \verb{data:} scheme.
the browser is able to handle URIs that use the \code{data:} scheme.
}
\item{\code{pixelratio} reports the "device pixel ratio" from the web browser,
or 1 if none is reported. The value is 2 for Apple Retina displays.
@@ -177,7 +177,7 @@ character vector, as in \code{input=c("x", "y")}. The format can be
}
\description{
Shiny server functions can optionally include \code{session} as a parameter
(e.g. \verb{function(input, output, session)}). The session object is an
(e.g. \code{function(input, output, session)}). The session object is an
environment that can be used to access information and functionality
relating to the session. The following list describes the items available
in the environment; they can be accessed using the \code{$} operator (for

View File

@@ -4,7 +4,8 @@
\alias{setBookmarkExclude}
\title{Exclude inputs from bookmarking}
\usage{
setBookmarkExclude(names = character(0), session = getDefaultReactiveDomain())
setBookmarkExclude(names = character(0),
session = getDefaultReactiveDomain())
}
\arguments{
\item{names}{A character vector containing names of inputs to exclude from

View File

@@ -6,14 +6,8 @@
\alias{shinyAppFile}
\title{Create a Shiny app object}
\usage{
shinyApp(
ui,
server,
onStart = NULL,
options = list(),
uiPattern = "/",
enableBookmarking = NULL
)
shinyApp(ui, server, onStart = NULL, options = list(),
uiPattern = "/", enableBookmarking = NULL)
shinyAppDir(appDir, options = list())
@@ -21,10 +15,7 @@ shinyAppFile(appFile, options = list())
}
\arguments{
\item{ui}{The UI definition of the app (for example, a call to
\code{fluidPage()} with nested controls).
If bookmarking is enabled (see \code{enableBookmarking}), this must be
a single argument function that returns the UI definition.}
\code{fluidPage()} with nested controls)}
\item{server}{A function with three parameters: \code{input}, \code{output}, and
\code{session}. The function is called once for each session ensuring that each
@@ -46,9 +37,11 @@ request. Note that the entire request path must match the regular
expression in order for the match to be considered successful.}
\item{enableBookmarking}{Can be one of \code{"url"}, \code{"server"}, or
\code{"disable"}. The default value, \code{NULL}, will respect the setting from
any previous calls to \code{\link[=enableBookmarking]{enableBookmarking()}}. See \code{\link[=enableBookmarking]{enableBookmarking()}}
for more information on bookmarking your app.}
\code{"disable"}. This is equivalent to calling the
\code{\link[=enableBookmarking]{enableBookmarking()}} function just before calling
\code{shinyApp()}. With the default value (\code{NULL}), the app will
respect the setting from any previous calls to \code{enableBookmarking()}.
See \code{\link[=enableBookmarking]{enableBookmarking()}} for more information.}
\item{appDir}{Path to directory that contains a Shiny app (i.e. a server.R
file and either ui.R or www/index.html)}

View File

@@ -4,12 +4,8 @@
\alias{shinyDeprecated}
\title{Print message for deprecated functions in Shiny}
\usage{
shinyDeprecated(
new = NULL,
msg = NULL,
old = as.character(sys.call(sys.parent()))[1L],
version = NULL
)
shinyDeprecated(new = NULL, msg = NULL,
old = as.character(sys.call(sys.parent()))[1L], version = NULL)
}
\arguments{
\item{new}{Name of replacement function.}

View File

@@ -44,18 +44,18 @@ be set globally with \code{options()} or locally (for a single app) with
app directory will be continually monitored for changes to files that
have the extensions: r, htm, html, js, css, png, jpg, jpeg, gif. If any
changes are detected, all connected Shiny sessions are reloaded. This
allows for fast feedback loops when tweaking Shiny UI.
Since monitoring for changes is expensive (we simply poll for last
allows for fast feedback loops when tweaking Shiny UI.\preformatted{Since monitoring for changes is expensive (we simply poll for last
modified times), this feature is intended only for development.
You can customize the file patterns Shiny will monitor by setting the
shiny.autoreload.pattern option. For example, to monitor only ui.R:
\code{options(shiny.autoreload.pattern = glob2rx("ui.R"))}
`options(shiny.autoreload.pattern = glob2rx("ui.R"))`
The default polling interval is 500 milliseconds. You can change this
by setting e.g. \code{options(shiny.autoreload.interval = 2000)} (every
by setting e.g. `options(shiny.autoreload.interval = 2000)` (every
two seconds).}
}
\item{shiny.deprecation.messages (defaults to \code{TRUE})}{This controls whether messages for
deprecated functions in Shiny will be printed. See
\code{\link[=shinyDeprecated]{shinyDeprecated()}} for more information.}

View File

@@ -5,15 +5,9 @@
\alias{removeNotification}
\title{Show or remove a notification}
\usage{
showNotification(
ui,
action = NULL,
duration = 5,
closeButton = TRUE,
id = NULL,
type = c("default", "message", "warning", "error"),
session = getDefaultReactiveDomain()
)
showNotification(ui, action = NULL, duration = 5, closeButton = TRUE,
id = NULL, type = c("default", "message", "warning", "error"),
session = getDefaultReactiveDomain())
removeNotification(id, session = getDefaultReactiveDomain())
}

Some files were not shown because too many files have changed in this diff Show More