mirror of
https://github.com/rstudio/shiny.git
synced 2026-01-10 23:48:01 -05:00
Compare commits
159 Commits
jeff/integ
...
reactive_c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
550b679e61 | ||
|
|
8ada448c51 | ||
|
|
106ad74d2b | ||
|
|
0a6260259a | ||
|
|
78f9132eb3 | ||
|
|
15476ac32e | ||
|
|
17fb5b9eae | ||
|
|
fd27a0dfa2 | ||
|
|
5ffe69ec6c | ||
|
|
f5723b2a4d | ||
|
|
01491cc696 | ||
|
|
568a3f28cf | ||
|
|
02219df480 | ||
|
|
e006ca51ee | ||
|
|
86f651f3ec | ||
|
|
212b33a0ce | ||
|
|
6b7a121161 | ||
|
|
c89da718b1 | ||
|
|
eef3ae8387 | ||
|
|
0975a61725 | ||
|
|
0c53d54347 | ||
|
|
cbbb04cf69 | ||
|
|
120baf0a6e | ||
|
|
685dc7cc3a | ||
|
|
2fbb2ac77b | ||
|
|
2832db7aba | ||
|
|
18f2471d7c | ||
|
|
ea28f5a61b | ||
|
|
fe9cc6038e | ||
|
|
5ed335c499 | ||
|
|
fd04b97496 | ||
|
|
4c9d281b59 | ||
|
|
2ee06a7cbf | ||
|
|
cf2ba90b1d | ||
|
|
c69f34d1e2 | ||
|
|
ccfcc5d8b4 | ||
|
|
210c248264 | ||
|
|
e3258657d0 | ||
|
|
dbc518bf53 | ||
|
|
cdbdb4510e | ||
|
|
e7ec5e5ba4 | ||
|
|
03d8a7f296 | ||
|
|
480035c065 | ||
|
|
b32c18cf72 | ||
|
|
337a6b276a | ||
|
|
06cf1f9477 | ||
|
|
190cfd2b7a | ||
|
|
63035b4d66 | ||
|
|
6a11c8fcb1 | ||
|
|
33ffb006e3 | ||
|
|
162e7f63a9 | ||
|
|
bb581eeec4 | ||
|
|
272c555bc5 | ||
|
|
fb64caab23 | ||
|
|
6f2a74a46d | ||
|
|
ec65a74492 | ||
|
|
ba791c42fa | ||
|
|
5896667c36 | ||
|
|
003c949d38 | ||
|
|
d31394254c | ||
|
|
1a497e246c | ||
|
|
d24276aa54 | ||
|
|
6ed21a3e6b | ||
|
|
8066f9ce96 | ||
|
|
a0276ec1ce | ||
|
|
2ab925a24c | ||
|
|
78fbad7d8d | ||
|
|
89be4bdce9 | ||
|
|
d09a064471 | ||
|
|
2b18ca5a6c | ||
|
|
6bc2f18bbf | ||
|
|
fbb892d84e | ||
|
|
4efb7c20e4 | ||
|
|
4beb1f07a6 | ||
|
|
45e640e5f9 | ||
|
|
e84beffee3 | ||
|
|
e07c7483a7 | ||
|
|
34ec7bf5eb | ||
|
|
01b20a4829 | ||
|
|
45ea898da4 | ||
|
|
fd34c5070f | ||
|
|
6c409d96c1 | ||
|
|
0cbe4bb3d4 | ||
|
|
d04a990235 | ||
|
|
4747c87632 | ||
|
|
f57452c7bf | ||
|
|
9a8e2eb675 | ||
|
|
8ef7f3cbe2 | ||
|
|
de30a65f01 | ||
|
|
0bcf613195 | ||
|
|
89fd9004d0 | ||
|
|
b2be108db1 | ||
|
|
6102c44b70 | ||
|
|
327cdc8e41 | ||
|
|
0bc3613989 | ||
|
|
30cea871f9 | ||
|
|
5f332fe4db | ||
|
|
7ee7f2716b | ||
|
|
5e8c39cb1e | ||
|
|
ee355200b3 | ||
|
|
986fbe2254 | ||
|
|
32f93a2be1 | ||
|
|
ab79065c13 | ||
|
|
77171b7894 | ||
|
|
cce8ddb84f | ||
|
|
648b7e5911 | ||
|
|
67a66fdc93 | ||
|
|
5fbaa26d05 | ||
|
|
1f4a3c4fd2 | ||
|
|
959dc7ffd4 | ||
|
|
0e34221cac | ||
|
|
0cad13b3a3 | ||
|
|
0776f71ca3 | ||
|
|
5a74e369ce | ||
|
|
799c5ac662 | ||
|
|
1080cf0ef4 | ||
|
|
867d49e3fb | ||
|
|
c7be406099 | ||
|
|
37257e77ce | ||
|
|
270d9ff0fc | ||
|
|
34b48598d9 | ||
|
|
5105ecb148 | ||
|
|
f47b151458 | ||
|
|
d3f15a58fc | ||
|
|
42f6adb7fa | ||
|
|
263f8a8e7d | ||
|
|
3a42d30cfd | ||
|
|
9275217a5a | ||
|
|
1fed19ad68 | ||
|
|
6a8a78abd1 | ||
|
|
de69f51084 | ||
|
|
c81a3f39fd | ||
|
|
6fcb925e34 | ||
|
|
8823b7280a | ||
|
|
ebadad97a8 | ||
|
|
a095c39626 | ||
|
|
fb9bcb44c3 | ||
|
|
38f593450a | ||
|
|
6d44f2c5cb | ||
|
|
d1786a64c4 | ||
|
|
616ae99c0b | ||
|
|
4d2ff80788 | ||
|
|
005295fd4c | ||
|
|
d6b46f8243 | ||
|
|
bac35e8f1b | ||
|
|
a003c4da85 | ||
|
|
0ae8e4fe8a | ||
|
|
26ba9bf94a | ||
|
|
85a2d41a72 | ||
|
|
c41d38bf61 | ||
|
|
b155e8480b | ||
|
|
e94f687573 | ||
|
|
5883082d01 | ||
|
|
75b53ffda1 | ||
|
|
324d9195c3 | ||
|
|
4ad115e024 | ||
|
|
f11d754cfe | ||
|
|
65019ce96f | ||
|
|
90e8fb2a57 |
@@ -5,14 +5,14 @@ matrix:
|
||||
r: release
|
||||
r_packages:
|
||||
- devtools
|
||||
- roxygen2
|
||||
- rprojroot
|
||||
script: ./tools/checkDocsCurrent.sh
|
||||
- name: "Javascript check"
|
||||
language: node_js
|
||||
cache: yarn
|
||||
script: ./tools/checkJSCurrent.sh
|
||||
node_js:
|
||||
- "10"
|
||||
- "12"
|
||||
- r: 3.2
|
||||
- r: 3.3
|
||||
- r: 3.4
|
||||
@@ -26,7 +26,3 @@ notifications:
|
||||
email:
|
||||
on_success: change
|
||||
on_failure: change
|
||||
slack:
|
||||
on_success: change
|
||||
secure: QoM0+hliVC4l2HYv126AkljG/uFvgwayW9IpuB5QNqjSukM122MhMDL7ZuMB9a2vWP24juzOTXiNIymgEspfnvvAMnZwYRBNWkuot2m8HIR2B9UjQLiztFnN1EAT+P+thz8Qax9TV2SOfXb2S2ZOeZmRTVkJctxkL8heAZadIC4=
|
||||
on_pull_requests: false
|
||||
|
||||
21
DESCRIPTION
21
DESCRIPTION
@@ -1,7 +1,7 @@
|
||||
Package: shiny
|
||||
Type: Package
|
||||
Title: Web Application Framework for R
|
||||
Version: 1.4.0.9000
|
||||
Version: 1.4.0.9002
|
||||
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),
|
||||
htmltools (>= 0.4.0.9001),
|
||||
R6 (>= 2.0),
|
||||
sourcetools,
|
||||
later (>= 1.0.0),
|
||||
@@ -78,7 +78,8 @@ Imports:
|
||||
tools,
|
||||
crayon,
|
||||
rlang (>= 0.4.0),
|
||||
fastmap (>= 1.0.0)
|
||||
fastmap (>= 1.0.0),
|
||||
withr
|
||||
Suggests:
|
||||
datasets,
|
||||
Cairo (>= 1.5-5),
|
||||
@@ -89,7 +90,12 @@ Suggests:
|
||||
ggplot2,
|
||||
reactlog (>= 1.0.0),
|
||||
magrittr,
|
||||
yaml
|
||||
shinytest,
|
||||
yaml,
|
||||
future,
|
||||
dygraphs
|
||||
Remotes:
|
||||
rstudio/htmltools
|
||||
URL: http://shiny.rstudio.com
|
||||
BugReports: https://github.com/rstudio/shiny/issues
|
||||
Collate:
|
||||
@@ -141,6 +147,8 @@ Collate:
|
||||
'jqueryui.R'
|
||||
'middleware-shiny.R'
|
||||
'middleware.R'
|
||||
'timer.R'
|
||||
'mock-session.R'
|
||||
'modal.R'
|
||||
'modules.R'
|
||||
'notifications.R'
|
||||
@@ -162,8 +170,9 @@ Collate:
|
||||
'snapshot.R'
|
||||
'tar.R'
|
||||
'test-export.R'
|
||||
'timer.R'
|
||||
'test-module.R'
|
||||
'test.R'
|
||||
'update-input.R'
|
||||
RoxygenNote: 6.1.1
|
||||
RoxygenNote: 7.1.0
|
||||
Encoding: UTF-8
|
||||
Roxygen: list(markdown = TRUE)
|
||||
|
||||
11
NAMESPACE
11
NAMESPACE
@@ -1,15 +1,18 @@
|
||||
# Generated by roxygen2: do not edit by hand
|
||||
|
||||
S3method("$",mockclientdata)
|
||||
S3method("$",reactivevalues)
|
||||
S3method("$",session_proxy)
|
||||
S3method("$",shinyoutput)
|
||||
S3method("$<-",reactivevalues)
|
||||
S3method("$<-",session_proxy)
|
||||
S3method("$<-",shinyoutput)
|
||||
S3method("[",mockclientdata)
|
||||
S3method("[",reactivevalues)
|
||||
S3method("[",shinyoutput)
|
||||
S3method("[<-",reactivevalues)
|
||||
S3method("[<-",shinyoutput)
|
||||
S3method("[[",mockclientdata)
|
||||
S3method("[[",reactivevalues)
|
||||
S3method("[[",session_proxy)
|
||||
S3method("[[",shinyoutput)
|
||||
@@ -34,6 +37,7 @@ export("conditionStackTrace<-")
|
||||
export(..stacktraceoff..)
|
||||
export(..stacktraceon..)
|
||||
export(HTML)
|
||||
export(MockShinySession)
|
||||
export(NS)
|
||||
export(Progress)
|
||||
export(a)
|
||||
@@ -142,6 +146,7 @@ export(maskReactiveContext)
|
||||
export(memoryCache)
|
||||
export(modalButton)
|
||||
export(modalDialog)
|
||||
export(moduleServer)
|
||||
export(navbarMenu)
|
||||
export(navbarPage)
|
||||
export(navlistPanel)
|
||||
@@ -212,6 +217,7 @@ export(runExample)
|
||||
export(runGadget)
|
||||
export(runGist)
|
||||
export(runGitHub)
|
||||
export(runTests)
|
||||
export(runUrl)
|
||||
export(safeError)
|
||||
export(selectInput)
|
||||
@@ -257,6 +263,8 @@ export(tagHasAttribute)
|
||||
export(tagList)
|
||||
export(tagSetChildren)
|
||||
export(tags)
|
||||
export(testModule)
|
||||
export(testServer)
|
||||
export(textAreaInput)
|
||||
export(textInput)
|
||||
export(textOutput)
|
||||
@@ -306,3 +314,6 @@ importFrom(fastmap,is.key_missing)
|
||||
importFrom(fastmap,key_missing)
|
||||
importFrom(grDevices,dev.cur)
|
||||
importFrom(grDevices,dev.set)
|
||||
importFrom(promises,"%...!%")
|
||||
importFrom(promises,"%...>%")
|
||||
importFrom(withr,with_options)
|
||||
|
||||
26
NEWS.md
26
NEWS.md
@@ -1,4 +1,4 @@
|
||||
shiny 1.4.0.9000
|
||||
shiny 1.4.0.9001
|
||||
===========
|
||||
|
||||
## Full changelog
|
||||
@@ -7,15 +7,35 @@ shiny 1.4.0.9000
|
||||
|
||||
### 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))
|
||||
|
||||
* `getDefaultReactiveDomain()` can now be called inside a `session$onSessionEnded` callback and will return the calling `session` information. ([#2757](https://github.com/rstudio/shiny/pull/2757))
|
||||
|
||||
* Added a `'function'` class to `reactive()` and `reactiveVal()` objects. ([#2793](https://github.com/rstudio/shiny/pull/2793))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
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 [#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))
|
||||
|
||||
### Documentation Updates
|
||||
|
||||
|
||||
shiny 1.4.0.1
|
||||
===========
|
||||
|
||||
Minor patch release to account for changes to the grid package that will be upcoming in the R 4.0 release ([#2776](https://github.com/rstudio/shiny/pull/2776)).
|
||||
|
||||
|
||||
shiny 1.4.0
|
||||
===========
|
||||
|
||||
@@ -85,7 +105,7 @@ shiny 1.3.2
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* 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 [#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 [#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
36
R/app.R
@@ -13,7 +13,10 @@
|
||||
#' object to `print()` or [runApp()].
|
||||
#'
|
||||
#' @param ui The UI definition of the app (for example, a call to
|
||||
#' `fluidPage()` with nested controls)
|
||||
#' `fluidPage()` with nested controls).
|
||||
#'
|
||||
#' If bookmarking is enabled (see `enableBookmarking`), this must be
|
||||
#' a single argument function that returns the UI definition.
|
||||
#' @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.
|
||||
@@ -30,11 +33,9 @@
|
||||
#' 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"`. 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.
|
||||
#' `"disable"`. The default value, `NULL`, will respect the setting from
|
||||
#' any previous calls to [enableBookmarking()]. See [enableBookmarking()]
|
||||
#' for more information on bookmarking your app.
|
||||
#' @return An object that represents the app. Printing the object or passing it
|
||||
#' to [runApp()] will run the app.
|
||||
#'
|
||||
@@ -283,7 +284,8 @@ initAutoReloadMonitor <- function(dir) {
|
||||
".*\\.(r|html?|js|css|png|jpe?g|gif)$")
|
||||
|
||||
lastValue <- NULL
|
||||
obs <- observe({
|
||||
observeLabel <- paste0("File Auto-Reload - '", basename(dir), "'")
|
||||
obs <- observe(label = observeLabel, {
|
||||
files <- sort(list.files(dir, pattern = filePattern, recursive = TRUE,
|
||||
ignore.case = TRUE))
|
||||
times <- file.info(files)$mtime
|
||||
@@ -313,14 +315,13 @@ 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, 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
|
||||
#' 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
|
||||
#' 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.
|
||||
@@ -339,8 +340,21 @@ 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)
|
||||
|
||||
@@ -231,8 +231,12 @@ column <- function(width, ..., offset = 0) {
|
||||
stop("column width must be between 1 and 12")
|
||||
|
||||
colClass <- paste0("col-sm-", width)
|
||||
if (offset > 0)
|
||||
colClass <- paste0(colClass, " col-sm-offset-", offset)
|
||||
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)
|
||||
}
|
||||
div(class = colClass, ...)
|
||||
}
|
||||
|
||||
@@ -566,7 +570,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
|
||||
|
||||
@@ -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,50 +793,43 @@ buildTabItem <- function(index, tabsetId, foundSelected, tabs = NULL,
|
||||
|
||||
#' Create a text output element
|
||||
#'
|
||||
#' Render a reactive output variable as text within an application page. The
|
||||
#' text will be included within an HTML `div` tag by default.
|
||||
#' 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.
|
||||
#'
|
||||
#' @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 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.
|
||||
#' @return A output element for use in UI.
|
||||
#' @examples
|
||||
#' ## Only run this example in interactive R sessions
|
||||
#' if (interactive()) {
|
||||
#' shinyApp(
|
||||
#' ui = basicPage(
|
||||
#' textInput("txt", "Enter the text to display below:"),
|
||||
#' verbatimTextOutput("default"),
|
||||
#' verbatimTextOutput("placeholder", placeholder = TRUE)
|
||||
#' textOutput("text"),
|
||||
#' verbatimTextOutput("verb")
|
||||
#' ),
|
||||
#' server = function(input, output) {
|
||||
#' output$default <- renderText({ input$txt })
|
||||
#' output$placeholder <- renderText({ input$txt })
|
||||
#' output$text <- renderText({ input$txt })
|
||||
#' output$verb <- 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"),
|
||||
|
||||
@@ -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",
|
||||
div(class = "input-daterange input-group input-group-sm",
|
||||
tags$input(
|
||||
class = "input-sm form-control",
|
||||
class = "form-control",
|
||||
type = "text",
|
||||
`data-date-language` = language,
|
||||
`data-date-week-start` = weekstart,
|
||||
@@ -109,9 +109,14 @@ dateRangeInput <- function(inputId, label, start = NULL, end = NULL,
|
||||
`data-initial-date` = start,
|
||||
`data-date-autoclose` = if (autoclose) "true" else "false"
|
||||
),
|
||||
span(class = "input-group-addon", separator),
|
||||
# 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
|
||||
)
|
||||
),
|
||||
tags$input(
|
||||
class = "input-sm form-control",
|
||||
class = "form-control",
|
||||
type = "text",
|
||||
`data-date-language` = language,
|
||||
`data-date-week-start` = weekstart,
|
||||
|
||||
@@ -11,8 +11,15 @@
|
||||
#' @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 MIME types; gives the browser a hint of
|
||||
#' what kind of files the server is expecting.
|
||||
#' @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 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.
|
||||
@@ -24,13 +31,7 @@
|
||||
#' ui <- fluidPage(
|
||||
#' sidebarLayout(
|
||||
#' sidebarPanel(
|
||||
#' fileInput("file1", "Choose CSV File",
|
||||
#' accept = c(
|
||||
#' "text/csv",
|
||||
#' "text/comma-separated-values,text/plain",
|
||||
#' ".csv")
|
||||
#' ),
|
||||
#' tags$hr(),
|
||||
#' fileInput("file1", "Choose CSV File", accept = ".csv"),
|
||||
#' checkboxInput("header", "Header", TRUE)
|
||||
#' ),
|
||||
#' mainPanel(
|
||||
@@ -41,17 +42,13 @@
|
||||
#'
|
||||
#' server <- function(input, output) {
|
||||
#' output$contents <- renderTable({
|
||||
#' # 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
|
||||
#' file <- input$file1
|
||||
#' ext <- tools::file_ext(file$datapath)
|
||||
#'
|
||||
#' if (is.null(inFile))
|
||||
#' return(NULL)
|
||||
#' req(file)
|
||||
#' validate(need(ext == "csv", "Please upload a csv file"))
|
||||
#'
|
||||
#' read.csv(inFile$datapath, header = input$header)
|
||||
#' read.csv(file$datapath, header = input$header)
|
||||
#' })
|
||||
#' }
|
||||
#'
|
||||
@@ -109,7 +106,8 @@ fileInput <- function(inputId, label, multiple = FALSE, accept = NULL,
|
||||
shinyInputLabel(inputId, label),
|
||||
|
||||
div(class = "input-group",
|
||||
tags$label(class = "input-group-btn",
|
||||
# input-group-prepend is for bootstrap 4 compat
|
||||
tags$label(class = "input-group-btn input-group-prepend",
|
||||
span(class = "btn btn-default btn-file",
|
||||
buttonLabel,
|
||||
inputTag
|
||||
@@ -122,7 +120,7 @@ fileInput <- function(inputId, label, multiple = FALSE, accept = NULL,
|
||||
|
||||
tags$div(
|
||||
id=paste(inputId, "_progress", sep=""),
|
||||
class="progress progress-striped active shiny-file-input-progress",
|
||||
class="progress active shiny-file-input-progress",
|
||||
tags$div(class="progress-bar")
|
||||
)
|
||||
)
|
||||
|
||||
160
R/insert-ui.R
160
R/insert-ui.R
@@ -1,55 +1,54 @@
|
||||
#' Insert UI objects
|
||||
#' Insert and remove UI objects
|
||||
#'
|
||||
#' 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
|
||||
#' 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
|
||||
#' 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. To remove any part of your UI, use [removeUI()].
|
||||
#' 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.
|
||||
#' 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).
|
||||
#'
|
||||
#' 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
|
||||
#' [here](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 <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 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()]
|
||||
#'
|
||||
#' `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.
|
||||
#' @examples
|
||||
#' ## Only run this example in interactive R sessions
|
||||
#' if (interactive()) {
|
||||
@@ -73,6 +72,26 @@
|
||||
#' # 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"),
|
||||
@@ -100,60 +119,7 @@ insertUI <- function(selector,
|
||||
}
|
||||
|
||||
|
||||
#' 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)
|
||||
#' }
|
||||
#' @rdname insertUI
|
||||
#' @export
|
||||
removeUI <- function(selector,
|
||||
multiple = FALSE,
|
||||
|
||||
435
R/mock-session.R
Normal file
435
R/mock-session.R
Normal file
@@ -0,0 +1,435 @@
|
||||
# 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.
|
||||
#' @noRd
|
||||
#' @export
|
||||
`$.mockclientdata` <- function(x, name) {
|
||||
if (name == "allowDataUriScheme") { return(TRUE) }
|
||||
if (name == "pixelratio") { return(1) }
|
||||
if (name == "url_protocol") { return("http:") }
|
||||
if (name == "url_hostname") { return("mocksession") }
|
||||
if (name == "url_port") { return(1234) }
|
||||
if (name == "url_pathname") { return("/mockpath") }
|
||||
if (name == "url_hash") { return("#mockhash") }
|
||||
if (name == "url_hash_initial") { return("#mockhash") }
|
||||
if (name == "url_search") { return("?mocksearch=1") }
|
||||
|
||||
clientRE <- "^output_(.+)_([^_]+)$"
|
||||
if(grepl(clientRE, name)) {
|
||||
# TODO: use proper regex group matching here instead of redundantly parsing
|
||||
el <- sub(clientRE, "\\1", name)
|
||||
att <- sub(clientRE, "\\2", name)
|
||||
|
||||
if (att == "width") {
|
||||
return(600)
|
||||
} else if (att == "height") {
|
||||
return(400)
|
||||
} else if (att == "hidden") {
|
||||
return(FALSE)
|
||||
}
|
||||
}
|
||||
warning("Unexpected clientdata attribute accessed: ", name)
|
||||
return(NULL)
|
||||
}
|
||||
|
||||
#' @noRd
|
||||
#' @export
|
||||
`[[.mockclientdata` <- `$.mockclientdata`
|
||||
|
||||
#' @noRd
|
||||
#' @export
|
||||
`[.mockclientdata` <- function(values, name) {
|
||||
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,
|
||||
public = list(
|
||||
#' @field env The environment associated with the session.
|
||||
env = NULL,
|
||||
#' @field singletons Hardcoded as empty. Needed for rendering HTML (i.e. renderUI)
|
||||
singletons = character(0),
|
||||
#' @field clientData 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())
|
||||
|
||||
# create output
|
||||
out <- .createOutputWriter(self)
|
||||
class(out) <- "shinyoutput"
|
||||
self$output <- out
|
||||
|
||||
# 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) {
|
||||
if (!isTRUE(once)) {
|
||||
return(private$flushCBs$register(fun))
|
||||
} else {
|
||||
dereg <- private$flushCBs$register(function() {
|
||||
dereg()
|
||||
fun()
|
||||
})
|
||||
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) {
|
||||
if (!isTRUE(once)) {
|
||||
return(private$flushedCBs$register(fun))
|
||||
} else {
|
||||
dereg <- private$flushedCBs$register(function() {
|
||||
dereg()
|
||||
fun()
|
||||
})
|
||||
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
|
||||
fileUrl = function(name, file, contentType='application/octet-stream') {
|
||||
bytes <- file.info(file)$size
|
||||
if (is.na(bytes))
|
||||
return(NULL)
|
||||
|
||||
fileData <- readBin(file, 'raw', n=bytes)
|
||||
b64 <- rawToBase64(fileData)
|
||||
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)
|
||||
})
|
||||
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) {
|
||||
id <- private$timer$schedule(millis, callback)
|
||||
|
||||
# Return a deregistration callback
|
||||
function() {
|
||||
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
|
||||
|
||||
while (msLeft > 0){
|
||||
t <- private$timer$timeToNextEvent()
|
||||
|
||||
if (is.infinite(t) || t <= 0 || msLeft < t){
|
||||
# Either there's no good upcoming event or we can't make it to it in the allotted time.
|
||||
break
|
||||
}
|
||||
msLeft <- msLeft - t
|
||||
private$timer$elapse(t)
|
||||
|
||||
# timerCallbacks must run before flushReact.
|
||||
private$timer$executeElapsed()
|
||||
private$flush()
|
||||
}
|
||||
|
||||
private$timer$elapse(msLeft)
|
||||
|
||||
# Run again in case our callbacks resulted in a scheduled
|
||||
# function that needs executing.
|
||||
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()
|
||||
},
|
||||
|
||||
#' @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))
|
||||
|
||||
obs <- observe({
|
||||
# We could just stash the promise, but we get an "unhandled promise error". This bypasses
|
||||
prom <- NULL
|
||||
tryCatch({
|
||||
v <- func(self, name)
|
||||
if (!promises::is.promise(v)){
|
||||
# Make our sync value into a promise
|
||||
prom <- promises::promise(function(resolve, reject){ resolve(v) })
|
||||
} else {
|
||||
prom <- v
|
||||
}
|
||||
}, error=function(e){
|
||||
# Error running value()
|
||||
prom <<- promises::promise(function(resolve, reject){ reject(e) })
|
||||
})
|
||||
|
||||
private$outs[[name]]$promise <- hybrid_chain(
|
||||
prom,
|
||||
function(v){
|
||||
list(val = v, err = NULL)
|
||||
}, catch=function(e){
|
||||
list(val = NULL, err = e)
|
||||
})
|
||||
})
|
||||
private$outs[[name]] <- list(obs = obs, func = func, 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]])) {
|
||||
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)){
|
||||
stop(v$err)
|
||||
} else {
|
||||
v$val
|
||||
}
|
||||
},
|
||||
|
||||
#' @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
|
||||
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()
|
||||
},
|
||||
#' @description Create and return a namespace-specific session proxy.
|
||||
#' @param namespace Character vector indicating a namespace.
|
||||
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(
|
||||
.input = NULL,
|
||||
flushCBs = NULL,
|
||||
flushedCBs = NULL,
|
||||
endedCBs = NULL,
|
||||
timer = NULL,
|
||||
closed = FALSE,
|
||||
outs = list(),
|
||||
returnedVal = NULL,
|
||||
|
||||
flush = function(){
|
||||
isolate(private$flushCBs$invoke(..stacktraceon = TRUE))
|
||||
shiny:::flushReact() # namespace to avoid calling our own method
|
||||
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)
|
||||
}
|
||||
# When you assign to returned, that implies that you just ran
|
||||
# the module. So we should proactively flush. We have to do this
|
||||
# here since flush is private.
|
||||
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")
|
||||
}
|
||||
warning("session$request doesn't currently simulate a realistic request on MockShinySession")
|
||||
new.env(parent=emptyenv())
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
90
R/modules.R
90
R/modules.R
@@ -37,24 +37,104 @@ createSessionProxy <- function(parentSession, ...) {
|
||||
`[[<-.session_proxy` <- `$<-.session_proxy`
|
||||
|
||||
|
||||
#' Invoke a Shiny module
|
||||
#' Shiny modules
|
||||
#'
|
||||
#' 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.
|
||||
#'
|
||||
#' @param module A Shiny module server function
|
||||
#' 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 id An ID string that corresponds with the ID used to call the module's
|
||||
#' UI function
|
||||
#' @param ... Additional parameters to pass to module server function
|
||||
#' UI function.
|
||||
#' @param ... For `callModule`, 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")
|
||||
#' }
|
||||
#' if (interactive()) {
|
||||
#' 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: ")
|
||||
#' }
|
||||
#' if (interactive()) {
|
||||
#' 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, c("ShinySession", "session_proxy", "MockShinySession"))) {
|
||||
stop("session must be a ShinySession or session_proxy object.")
|
||||
}
|
||||
childScope <- session$makeScope(id)
|
||||
|
||||
withReactiveDomain(childScope, {
|
||||
|
||||
74
R/progress.R
74
R/progress.R
@@ -20,50 +20,12 @@
|
||||
#' [`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`.
|
||||
#' @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.
|
||||
#' 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`.
|
||||
#'
|
||||
#' @examples
|
||||
#' ## Only run examples in interactive R sessions
|
||||
@@ -99,6 +61,17 @@ 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"))
|
||||
@@ -117,6 +90,11 @@ 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.")
|
||||
@@ -143,6 +121,11 @@ 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
|
||||
@@ -151,12 +134,17 @@ 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.")
|
||||
|
||||
@@ -222,7 +222,7 @@ reactiveVal <- function(value = NULL, label = NULL) {
|
||||
rv$set(x)
|
||||
}
|
||||
},
|
||||
class = c("reactiveVal", "reactive"),
|
||||
class = c("reactiveVal", "reactive", "function"),
|
||||
label = label,
|
||||
.impl = rv
|
||||
)
|
||||
@@ -969,7 +969,7 @@ reactive <- function(x, env = parent.frame(), quoted = FALSE, label = NULL,
|
||||
if (length(srcref) >= 2) attr(label, "srcref") <- srcref[[2]]
|
||||
attr(label, "srcfile") <- srcFileOfRef(srcref[[1]])
|
||||
o <- Observable$new(fun, label, domain, ..stacktraceon = ..stacktraceon)
|
||||
structure(o$getValue, observable = o, class = c("reactiveExpr", "reactive"))
|
||||
structure(o$getValue, observable = o, class = c("reactiveExpr", "reactive", "function"))
|
||||
}
|
||||
|
||||
# Given the srcref to a reactive expression, attempts to figure out what the
|
||||
@@ -2362,20 +2362,24 @@ 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 f() changes.
|
||||
# Responsible for tracking when r() 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 <- getTime(domain) + millis()/1000
|
||||
v$when <- getDomainTimeMs(domain) + millis()
|
||||
}, label = "debounce tracker", domain = domain, priority = priority)
|
||||
|
||||
# This observer is the timer. It rests until v$when elapses, then touches
|
||||
@@ -2384,13 +2388,13 @@ debounce <- function(r, millis, priority = 100, domain = getDefaultReactiveDomai
|
||||
if (is.null(v$when))
|
||||
return()
|
||||
|
||||
now <- getTime(domain)
|
||||
now <- getDomainTimeMs(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) * 1000)
|
||||
invalidateLater(v$when - now)
|
||||
}
|
||||
}, label = "debounce timer", domain = domain, priority = priority)
|
||||
|
||||
@@ -2435,12 +2439,12 @@ throttle <- function(r, millis, priority = 100, domain = getDefaultReactiveDomai
|
||||
if (is.null(v$lastTriggeredAt)) {
|
||||
0
|
||||
} else {
|
||||
max(0, (v$lastTriggeredAt + millis()/1000) - getTime(domain)) * 1000
|
||||
max(0, v$lastTriggeredAt + millis() - getDomainTimeMs(domain))
|
||||
}
|
||||
}
|
||||
|
||||
trigger <- function() {
|
||||
v$lastTriggeredAt <- getTime(domain)
|
||||
v$lastTriggeredAt <- getDomainTimeMs(domain)
|
||||
# Mod by 999999999 to get predictable overflow behavior
|
||||
v$trigger <- isolate(v$trigger) %% 999999999 + 1
|
||||
v$pending <- FALSE
|
||||
|
||||
@@ -889,6 +889,14 @@ find_panel_info_non_api <- function(b, ggplot_format) {
|
||||
})
|
||||
}
|
||||
|
||||
# Use public API for getting the unit's type (grid::unitType(), added in R 4.0)
|
||||
# https://github.com/wch/r-source/blob/f9b8a42/src/library/grid/R/unit.R#L179
|
||||
getUnitType <- function(u) {
|
||||
tryCatch(
|
||||
get("unitType", envir = asNamespace("grid"))(u),
|
||||
error = function(e) attr(u, "unit", exact = TRUE)
|
||||
)
|
||||
}
|
||||
|
||||
# Given a gtable object, return the x and y ranges (in pixel dimensions)
|
||||
find_panel_ranges <- function(g, res) {
|
||||
@@ -904,11 +912,11 @@ find_panel_ranges <- function(g, res) {
|
||||
if (inherits(x, "unit.list")) {
|
||||
# For ggplot2 <= 1.0.1
|
||||
vapply(x, FUN.VALUE = logical(1), function(u) {
|
||||
isTRUE(attr(u, "unit", exact = TRUE) == "null")
|
||||
isTRUE(getUnitType(u) == "null")
|
||||
})
|
||||
} else {
|
||||
# For later versions of ggplot2
|
||||
attr(x, "unit", exact = TRUE) == "null"
|
||||
getUnitType(x) == "null"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -948,7 +956,11 @@ find_panel_ranges <- function(g, res) {
|
||||
|
||||
# The plotting panels all are 'null' units.
|
||||
null_sizes <- rep(NA_real_, length(rel_sizes))
|
||||
null_sizes[null_idx] <- as.numeric(rel_sizes[null_idx])
|
||||
# Workaround for `[.unit` forbidding zero-length subsets
|
||||
# https://github.com/wch/r-source/blob/f9b8a42/src/library/grid/R/unit.R#L448-L450
|
||||
if (length(null_idx)) {
|
||||
null_sizes[null_idx] <- as.numeric(rel_sizes[null_idx])
|
||||
}
|
||||
|
||||
# Total size allocated for panels is the total image size minus absolute
|
||||
# (non-panel) elements.
|
||||
|
||||
@@ -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(charToRaw("\003\xe9"), msg)
|
||||
identical(as.raw(c(0x03, 0xe9)), msg)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
16
R/shiny.R
16
R/shiny.R
@@ -723,9 +723,12 @@ 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
|
||||
},
|
||||
@@ -959,7 +962,9 @@ ShinySession <- R6Class(
|
||||
output$suspend()
|
||||
}
|
||||
# ..stacktraceon matches with the top-level ..stacktraceoff..
|
||||
private$closedCallbacks$invoke(onError = printError, ..stacktraceon = TRUE)
|
||||
withReactiveDomain(self, {
|
||||
private$closedCallbacks$invoke(onError = printError, ..stacktraceon = TRUE)
|
||||
})
|
||||
},
|
||||
isClosed = function() {
|
||||
return(self$closed)
|
||||
@@ -1294,6 +1299,9 @@ ShinySession <- R6Class(
|
||||
|
||||
getCurrentOutputInfo = function() {
|
||||
name <- private$currentOutputName
|
||||
if (is.null(name)) {
|
||||
return(NULL)
|
||||
}
|
||||
|
||||
tmp_info <- private$outputInfo[[name]] %OR% list(name = name)
|
||||
|
||||
@@ -2093,6 +2101,10 @@ 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
|
||||
|
||||
169
R/test-module.R
Normal file
169
R/test-module.R
Normal file
@@ -0,0 +1,169 @@
|
||||
|
||||
|
||||
#' 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
|
||||
#' @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]_.
|
||||
#' @return The result of evaluating `expr`.
|
||||
#' @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(
|
||||
module,
|
||||
quosure = rlang::enquo(expr),
|
||||
dots = rlang::list2(...),
|
||||
env = rlang::caller_env()
|
||||
)
|
||||
}
|
||||
|
||||
#' @noRd
|
||||
#' @importFrom withr with_options
|
||||
.testModule <- function(module, quosure, dots, env) {
|
||||
# Modify the module function locally by inserting `session$env <-
|
||||
# environment()` at the beginning of its body. The dynamic environment of the
|
||||
# module function is saved so that it may be referenced after the module
|
||||
# function has returned. The saved dynamic environment is the basis for the
|
||||
# `data` argument of tidy_eval() when used below to evaluate `quosure`, the
|
||||
# test code expression.
|
||||
body(module) <- rlang::expr({
|
||||
session$env <- base::environment()
|
||||
!!!body(module)
|
||||
})
|
||||
|
||||
session <- MockShinySession$new()
|
||||
on.exit(if (!session$isClosed()) session$close())
|
||||
args <- append(dots, list(input = session$input, output = session$output, session = session))
|
||||
|
||||
isolate(
|
||||
withReactiveDomain(
|
||||
session,
|
||||
withr::with_options(list(`shiny.allowoutputreads`=TRUE), {
|
||||
# Assigning to `$returned` causes a flush to happen automatically.
|
||||
session$returned <- do.call(module, args)
|
||||
})
|
||||
)
|
||||
)
|
||||
|
||||
# Evaluate `quosure` in a reactive context, and in the provided `env`, but
|
||||
# with `env` masked by a shallow view of `session$env`, the environment that
|
||||
# was saved when the module function was invoked. flush is not needed before
|
||||
# entering the loop because the first expr executed is `{`.
|
||||
isolate({
|
||||
withReactiveDomain(
|
||||
session,
|
||||
withr::with_options(list(`shiny.allowoutputreads`=TRUE), {
|
||||
rlang::eval_tidy(
|
||||
quosure,
|
||||
data = rlang::as_data_mask(as.list(session$env)),
|
||||
env = env
|
||||
)
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
#' Test an app's server-side logic
|
||||
#' @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)){
|
||||
appDir <- findApp()
|
||||
}
|
||||
|
||||
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)) {
|
||||
fn_formals$session <- bquote()
|
||||
formals(server) <- fn_formals
|
||||
}
|
||||
|
||||
# Test the server function almost as if it were a module. `dots` is empty
|
||||
# because server functions never take additional arguments.
|
||||
.testModule(
|
||||
server,
|
||||
quosure = rlang::enquo(expr),
|
||||
dots = list(),
|
||||
env = rlang::caller_env()
|
||||
)
|
||||
}
|
||||
|
||||
findApp <- function(startDir="."){
|
||||
dir <- normalizePath(startDir)
|
||||
|
||||
# The loop will either return or stop() itself.
|
||||
while (TRUE){
|
||||
if(file.exists.ci(file.path(dir, "app.R")) || file.exists.ci(file.path(dir, "server.R"))){
|
||||
return(dir)
|
||||
}
|
||||
|
||||
# Move up a directory
|
||||
origDir <- dir
|
||||
dir <- dirname(dir)
|
||||
|
||||
# Testing for "root" path can be tricky. OSs differ and on Windows, network shares
|
||||
# might have a \\ prefix. Easier to just see if we got stuck and abort.
|
||||
if (dir == origDir){
|
||||
# We can go no further.
|
||||
stop("No shiny app was found in ", startDir, " or any of its parent directories")
|
||||
}
|
||||
}
|
||||
}
|
||||
107
R/test.R
Normal file
107
R/test.R
Normal file
@@ -0,0 +1,107 @@
|
||||
|
||||
#' 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"))
|
||||
}
|
||||
61
R/timer.R
61
R/timer.R
@@ -1,10 +1,9 @@
|
||||
# Return the current time, in milliseconds from epoch, with
|
||||
# unspecified time zone.
|
||||
getNow <- function() {
|
||||
# Return the current time, in milliseconds from epoch.
|
||||
getTimeMs <- function() {
|
||||
as.numeric(Sys.time()) * 1000
|
||||
}
|
||||
|
||||
BaseTimerCallbacks <- R6Class(
|
||||
TimerCallbacks <- R6Class(
|
||||
'TimerCallbacks',
|
||||
portable = FALSE,
|
||||
class = FALSE,
|
||||
@@ -14,7 +13,7 @@ BaseTimerCallbacks <- R6Class(
|
||||
.times = data.frame(),
|
||||
.now = 'Function',
|
||||
|
||||
initialize = function(nowFn=getNow) {
|
||||
initialize = function(nowFn = getTimeMs) {
|
||||
.funcs <<- Map$new()
|
||||
.now <<- nowFn
|
||||
},
|
||||
@@ -62,7 +61,7 @@ BaseTimerCallbacks <- R6Class(
|
||||
},
|
||||
takeElapsed = function() {
|
||||
t <- .now()
|
||||
elapsed <- .times$time < .now()
|
||||
elapsed <- .times$time <= .now()
|
||||
result <- .times[elapsed,]
|
||||
.times <<- .times[!elapsed,]
|
||||
|
||||
@@ -88,34 +87,24 @@ BaseTimerCallbacks <- R6Class(
|
||||
)
|
||||
)
|
||||
|
||||
TimerCallbacks <- R6Class(
|
||||
'TimerCallbacks',
|
||||
inherit=BaseTimerCallbacks,
|
||||
portable = FALSE,
|
||||
class = FALSE,
|
||||
public = list(
|
||||
# Empty constructor defaults to the getNow implementation
|
||||
initialize = function() {
|
||||
super$initialize(getNow)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
MockableTimerCallbacks <- R6Class(
|
||||
'MockableTimerCallbacks',
|
||||
inherit=BaseTimerCallbacks,
|
||||
inherit = TimerCallbacks,
|
||||
portable = FALSE,
|
||||
class = FALSE,
|
||||
public = list(
|
||||
# Empty constructor defaults to the getNow implementation
|
||||
initialize = function() {
|
||||
super$initialize(self$now)
|
||||
super$initialize(self$mockNow)
|
||||
},
|
||||
now = function(){
|
||||
mockNow = function() {
|
||||
return(private$time)
|
||||
},
|
||||
elapse = function(millis){
|
||||
private$time <<- private$time + millis
|
||||
elapse = function(millis) {
|
||||
private$time <- private$time + millis
|
||||
},
|
||||
getElapsed = function() {
|
||||
private$time
|
||||
}
|
||||
), private = list(
|
||||
time = 0L
|
||||
@@ -137,24 +126,22 @@ scheduleTask <- function(millis, callback) {
|
||||
#' session scheduler, but if it doesn't exist, use the global one.
|
||||
#' @noRd
|
||||
defineScheduler <- function(session){
|
||||
if (!is.null(session)){
|
||||
if (!is.null(session$scheduleTask)){
|
||||
return(session$scheduleTask)
|
||||
}
|
||||
if (!is.null(session) && !is.null(session$.scheduleTask)){
|
||||
return(session$.scheduleTask)
|
||||
}
|
||||
scheduleTask
|
||||
}
|
||||
|
||||
|
||||
#' 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.
|
||||
#' 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.
|
||||
#' @noRd
|
||||
getTime <- function(session){
|
||||
if (!is.null(session)){
|
||||
if (!is.null(session$now)){
|
||||
return(session$now())
|
||||
}
|
||||
getDomainTimeMs <- function(session){
|
||||
if (!is.null(session) && !is.null(session$.now)){
|
||||
return(session$.now())
|
||||
} else {
|
||||
getTimeMs()
|
||||
}
|
||||
Sys.time()
|
||||
}
|
||||
|
||||
10
appveyor.yml
10
appveyor.yml
@@ -11,14 +11,16 @@ install:
|
||||
ps: Bootstrap
|
||||
|
||||
cache:
|
||||
- C:\RLibrary
|
||||
# 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
|
||||
|
||||
# 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:
|
||||
|
||||
@@ -77,7 +77,6 @@ reference:
|
||||
- outputOptions
|
||||
- tableOutput
|
||||
- textOutput
|
||||
- verbatimTextOutput
|
||||
- downloadButton
|
||||
- Progress
|
||||
- withProgress
|
||||
@@ -99,7 +98,6 @@ 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:
|
||||
@@ -209,9 +207,15 @@ reference:
|
||||
desc: Functions for modularizing Shiny apps
|
||||
contents:
|
||||
- NS
|
||||
- callModule
|
||||
- moduleServer
|
||||
- title: Embedding
|
||||
desc: Functions that are intended for third-party packages that embed Shiny applications.
|
||||
contents:
|
||||
- shinyApp
|
||||
- maskReactiveContext
|
||||
- title: Testing
|
||||
desc: Functions intended for testing of Shiny components
|
||||
contents:
|
||||
- runTests
|
||||
- testModule
|
||||
- MockShinySession
|
||||
|
||||
@@ -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 input-sm",
|
||||
sLengthSelect: "form-control input-sm"
|
||||
sFilterInput: "form-control form-control-sm input-sm",
|
||||
sLengthSelect: "form-control form-control-sm input-sm"
|
||||
} );
|
||||
|
||||
|
||||
|
||||
@@ -401,6 +401,9 @@ 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.disabled:hover,
|
||||
.datepicker table tbody tr td span.disabled,
|
||||
.datepicker table tbody tr td span.disabled:hover {
|
||||
color: #aaa;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
@@ -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.9000"; // Version number inserted by Grunt
|
||||
exports.version = "1.4.0.9002"; // 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 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>',
|
||||
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>',
|
||||
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 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>');
|
||||
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>');
|
||||
|
||||
$progress.attr('id', message.id);
|
||||
$container.append($progress);
|
||||
|
||||
File diff suppressed because one or more lines are too long
8
inst/www/shared/shiny.min.js
vendored
8
inst/www/shared/shiny.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -2,13 +2,18 @@
|
||||
\alias{HTML}
|
||||
\title{Mark Characters as HTML}
|
||||
\usage{
|
||||
HTML(text, ...)
|
||||
HTML(text, ..., .noWS = NULL)
|
||||
}
|
||||
\arguments{
|
||||
\item{text}{The text value to mark with HTML}
|
||||
|
||||
\item{...}{Any additional values to be converted to character and
|
||||
concatenated together}
|
||||
|
||||
\item{.noWS}{Character vector used to omit some of the whitespace that would
|
||||
normally be written around this HTML. Valid options include \code{before},
|
||||
\code{after}, and \code{outside} (equivalent to \code{before} and
|
||||
\code{end}).}
|
||||
}
|
||||
\value{
|
||||
The same value, but marked as HTML.
|
||||
|
||||
687
man/MockShinySession.Rd
Normal file
687
man/MockShinySession.Rd
Normal file
@@ -0,0 +1,687 @@
|
||||
% 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>}}
|
||||
\if{latex}{\out{\hypertarget{method-reactlog}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-incrementBusyCount}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-new}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-onFlush}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-onFlushed}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-onEnded}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-isEnded}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-isClosed}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-close}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-cycleStartAction}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-fileUrl}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-setInputs}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-.scheduleTask}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-elapse}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-.now}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-defineOutput}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-getOutput}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-registerDataObj}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-allowReconnect}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-reload}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-resetBrush}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-sendCustomMessage}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-sendBinaryMessage}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-sendInputMessage}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-setBookmarkExclude}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-getBookmarkExclude}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-onBookmark}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-onBookmarked}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-doBookmark}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-onRestore}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-onRestored}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-exportTestValues}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-getTestSnapshotUrl}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-ns}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-flushReact}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-makeScope}{}}}
|
||||
\subsection{Method \code{makeScope()}}{
|
||||
Create and return a namespace-specific session proxy.
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$makeScope(namespace)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{namespace}}{Character vector indicating a namespace.}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-clone"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-clone}{}}}
|
||||
\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>}}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,9 @@
|
||||
\alias{NS}
|
||||
\alias{ns.sep}
|
||||
\title{Namespaced IDs for inputs/outputs}
|
||||
\format{An object of class \code{character} of length 1.}
|
||||
\format{
|
||||
An object of class \code{character} of length 1.
|
||||
}
|
||||
\usage{
|
||||
NS(namespace, id = NULL)
|
||||
|
||||
|
||||
224
man/Progress.Rd
224
man/Progress.Rd
@@ -1,47 +1,16 @@
|
||||
% 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)}
|
||||
\arguments{
|
||||
\item{session}{The Shiny session object, as provided by
|
||||
\code{shinyServer} to the server function.}
|
||||
|
||||
\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.
|
||||
Reporting progress (object-oriented API)
|
||||
|
||||
Reporting progress (object-oriented API)
|
||||
}
|
||||
\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
|
||||
@@ -59,26 +28,6 @@ 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
|
||||
@@ -110,4 +59,165 @@ shinyApp(ui, server)
|
||||
\seealso{
|
||||
\code{\link[=withProgress]{withProgress()}}
|
||||
}
|
||||
\keyword{datasets}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-new}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-set}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-inc}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-getMin}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-getMax}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-getValue}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-close}{}}}
|
||||
\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>}}
|
||||
\if{latex}{\out{\hypertarget{method-clone}{}}}
|
||||
\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>}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,30 @@
|
||||
\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
|
||||
@@ -53,7 +70,7 @@ An HTML element or list of elements.
|
||||
Creates a panel whose contents are absolutely positioned.
|
||||
}
|
||||
\details{
|
||||
The \code{absolutePanel} function creates a \code{<div>} tag whose CSS
|
||||
The \code{absolutePanel} function creates a \verb{<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
|
||||
|
||||
@@ -67,13 +67,20 @@ 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}
|
||||
|
||||
@@ -4,10 +4,13 @@
|
||||
\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
|
||||
|
||||
@@ -4,9 +4,17 @@
|
||||
\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"},
|
||||
|
||||
@@ -4,8 +4,15 @@
|
||||
\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.}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
% 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}
|
||||
}
|
||||
@@ -4,9 +4,16 @@
|
||||
\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.}
|
||||
@@ -93,13 +100,20 @@ 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}
|
||||
|
||||
@@ -45,13 +45,20 @@ 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}
|
||||
|
||||
@@ -4,8 +4,12 @@
|
||||
\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
|
||||
|
||||
@@ -4,10 +4,21 @@
|
||||
\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.}
|
||||
@@ -120,14 +131,20 @@ 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}
|
||||
|
||||
@@ -4,10 +4,21 @@
|
||||
\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.}
|
||||
@@ -124,13 +135,20 @@ 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}
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
\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).}
|
||||
@@ -49,7 +47,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.
|
||||
|
||||
\code{ooo-oo-oo---- => -----------o-}
|
||||
\verb{ooo-oo-oo---- => -----------o-}
|
||||
|
||||
(In this graphical depiction, each character represents a unit of time, and
|
||||
the time window is 3 characters.)
|
||||
@@ -61,7 +59,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.
|
||||
|
||||
\code{ooo-oo-oo---- => o--o--o--o---}
|
||||
\verb{ooo-oo-oo---- => o--o--o--o---}
|
||||
}
|
||||
\section{Limitations}{
|
||||
|
||||
|
||||
@@ -4,9 +4,17 @@
|
||||
\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
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
\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
|
||||
|
||||
@@ -4,8 +4,12 @@
|
||||
\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
|
||||
@@ -62,7 +66,7 @@ shinyApp(
|
||||
})
|
||||
|
||||
output$values <- renderText({
|
||||
paste0("vals$x: ", vals$x, "\\ny: ", y())
|
||||
paste0("vals$x: ", vals$x, "\ny: ", y())
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
@@ -4,9 +4,15 @@
|
||||
\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.}
|
||||
@@ -17,8 +23,17 @@ fileInput(inputId, label, multiple = FALSE, accept = NULL,
|
||||
multiple files at once. \strong{Does not work on older browsers, including
|
||||
Internet Explorer 9 and earlier.}}
|
||||
|
||||
\item{accept}{A character vector of MIME types; gives the browser a hint of
|
||||
what kind of files the server is expecting.}
|
||||
\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{width}{The width of the input, e.g. \code{'400px'}, or \code{'100\%'};
|
||||
see \code{\link[=validateCssUnit]{validateCssUnit()}}.}
|
||||
@@ -33,7 +48,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 \code{Server value} section.
|
||||
to a dataframe. See the \verb{Server value} section.
|
||||
}
|
||||
\section{Server value}{
|
||||
|
||||
@@ -60,13 +75,7 @@ if (interactive()) {
|
||||
ui <- fluidPage(
|
||||
sidebarLayout(
|
||||
sidebarPanel(
|
||||
fileInput("file1", "Choose CSV File",
|
||||
accept = c(
|
||||
"text/csv",
|
||||
"text/comma-separated-values,text/plain",
|
||||
".csv")
|
||||
),
|
||||
tags$hr(),
|
||||
fileInput("file1", "Choose CSV File", accept = ".csv"),
|
||||
checkboxInput("header", "Header", TRUE)
|
||||
),
|
||||
mainPanel(
|
||||
@@ -77,17 +86,13 @@ ui <- fluidPage(
|
||||
|
||||
server <- function(input, output) {
|
||||
output$contents <- renderTable({
|
||||
# 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
|
||||
file <- input$file1
|
||||
ext <- tools::file_ext(file$datapath)
|
||||
|
||||
if (is.null(inFile))
|
||||
return(NULL)
|
||||
req(file)
|
||||
validate(need(ext == "csv", "Please upload a csv file"))
|
||||
|
||||
read.csv(inFile$datapath, header = input$header)
|
||||
read.csv(file$datapath, header = input$header)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -96,13 +101,20 @@ 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}
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
\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.}
|
||||
@@ -42,11 +41,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 (\code{<div>} and \code{<body>}) have
|
||||
because the plot's containing elements (\verb{<div>} and \verb{<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 \code{<body>} height at 100\% of the window height.
|
||||
\code{fillPage} fixes the \verb{<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
|
||||
@@ -83,9 +82,13 @@ 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}
|
||||
|
||||
@@ -67,9 +67,13 @@ 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}
|
||||
|
||||
@@ -32,9 +32,13 @@ 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}
|
||||
|
||||
@@ -101,9 +101,13 @@ 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}
|
||||
|
||||
@@ -9,6 +9,11 @@ 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.
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ getUrlHash(session = getDefaultReactiveDomain())
|
||||
\value{
|
||||
For \code{getQueryString}, a named list. For example, the query
|
||||
string \code{?param1=value1¶m2=value2} becomes \code{list(param1 = value1, param2 = value2)}. For \code{getUrlHash}, a character vector with
|
||||
the hash (including the leading \code{#} symbol).
|
||||
the hash (including the leading \verb{#} 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
|
||||
\code{updateQueryString(_yourNewQueryString_, mode = "push")}. The default
|
||||
\verb{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)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
@@ -4,8 +4,13 @@
|
||||
\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"},
|
||||
|
||||
@@ -5,11 +5,14 @@
|
||||
\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}
|
||||
|
||||
@@ -7,14 +7,30 @@
|
||||
\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())
|
||||
}
|
||||
|
||||
@@ -2,17 +2,36 @@
|
||||
% Please edit documentation in R/insert-ui.R
|
||||
\name{insertUI}
|
||||
\alias{insertUI}
|
||||
\title{Insert UI objects}
|
||||
\alias{removeUI}
|
||||
\title{Insert and remove UI objects}
|
||||
\usage{
|
||||
insertUI(selector, where = c("beforeBegin", "afterBegin", "beforeEnd",
|
||||
"afterEnd"), ui, multiple = FALSE, immediate = FALSE,
|
||||
session = getDefaultReactiveDomain())
|
||||
insertUI(
|
||||
selector,
|
||||
where = c("beforeBegin", "afterBegin", "beforeEnd", "afterEnd"),
|
||||
ui,
|
||||
multiple = FALSE,
|
||||
immediate = FALSE,
|
||||
session = getDefaultReactiveDomain()
|
||||
)
|
||||
|
||||
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) relative to which you want to insert your
|
||||
UI object.}
|
||||
\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{where}{Where your UI object should go relative to the selector:
|
||||
\describe{
|
||||
@@ -23,8 +42,7 @@ first child}
|
||||
last child (default)}
|
||||
\item{\code{afterEnd}}{After the selector element itself}
|
||||
}
|
||||
Adapted from
|
||||
\href{https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML}{here}.}
|
||||
Adapted from \url{https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML}.}
|
||||
|
||||
\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
|
||||
@@ -39,25 +57,27 @@ 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 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{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{session}{The shiny session within which to call \code{insertUI}.}
|
||||
\item{session}{The shiny session. Advanced use only.}
|
||||
}
|
||||
\description{
|
||||
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
|
||||
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
|
||||
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. To remove any part of your UI, use \code{\link[=removeUI]{removeUI()}}.
|
||||
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.
|
||||
}
|
||||
\examples{
|
||||
## Only run this example in interactive R sessions
|
||||
@@ -82,7 +102,24 @@ 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()}}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,16 @@
|
||||
\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}
|
||||
|
||||
@@ -4,13 +4,16 @@
|
||||
\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 \code{R/} directory should
|
||||
\item{renv}{The environmeny in which the files in the \verb{R/} directory should
|
||||
be evaluated.}
|
||||
|
||||
\item{globalrenv}{The environment in which \code{global.R} should be evaluated. If
|
||||
@@ -18,19 +21,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 \code{R/} directory
|
||||
this function loads any top-level supporting \code{.R} files in the \verb{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, 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
|
||||
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
|
||||
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
|
||||
\code{R/} directory.
|
||||
\verb{R/} directory.
|
||||
}
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
\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
|
||||
|
||||
@@ -4,9 +4,15 @@
|
||||
\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
|
||||
|
||||
@@ -4,8 +4,14 @@
|
||||
\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.}
|
||||
|
||||
105
man/moduleServer.Rd
Normal file
105
man/moduleServer.Rd
Normal file
@@ -0,0 +1,105 @@
|
||||
% 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")
|
||||
}
|
||||
if (interactive()) {
|
||||
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: ")
|
||||
}
|
||||
if (interactive()) {
|
||||
shinyApp(ui, server)
|
||||
}
|
||||
|
||||
}
|
||||
\seealso{
|
||||
\url{http://shiny.rstudio.com/articles/modules.html}
|
||||
}
|
||||
@@ -5,11 +5,22 @@
|
||||
\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)
|
||||
}
|
||||
@@ -21,7 +32,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 \code{input$}\emph{\code{id}} in your
|
||||
\item{id}{If provided, you can use \verb{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()}}.}
|
||||
@@ -106,9 +117,13 @@ 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}
|
||||
|
||||
@@ -4,13 +4,19 @@
|
||||
\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 \code{input$}\emph{\code{id}} in your
|
||||
\item{id}{If provided, you can use \verb{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()}}.}
|
||||
|
||||
@@ -4,9 +4,18 @@
|
||||
\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.}
|
||||
|
||||
@@ -4,8 +4,15 @@
|
||||
\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.}
|
||||
@@ -52,13 +59,20 @@ 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}
|
||||
|
||||
@@ -4,10 +4,17 @@
|
||||
\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
|
||||
|
||||
@@ -5,18 +5,35 @@
|
||||
\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;
|
||||
@@ -148,7 +165,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 \code{eventReactive([...], ignoreInit = TRUE)} if you want
|
||||
then you should use \verb{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).
|
||||
|
||||
@@ -202,7 +219,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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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 ====
|
||||
}
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
\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.}
|
||||
@@ -54,13 +53,20 @@ 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}
|
||||
|
||||
@@ -5,15 +5,35 @@
|
||||
\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.}
|
||||
@@ -95,7 +115,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 \code{input$}
|
||||
occur, the mouse coordinates will be sent to the server as \verb{input$}
|
||||
variables, as specified by \code{click}, \code{dblclick}, \code{hover}, or
|
||||
\code{brush}.
|
||||
|
||||
@@ -175,15 +195,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({
|
||||
@@ -255,15 +275,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)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,8 +4,14 @@
|
||||
\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.}
|
||||
|
||||
@@ -4,9 +4,16 @@
|
||||
\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.}
|
||||
@@ -108,13 +115,20 @@ 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}
|
||||
|
||||
@@ -5,8 +5,14 @@
|
||||
\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)
|
||||
}
|
||||
|
||||
@@ -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 \code{SELECT MAX(timestamp) FROM table} and
|
||||
a value retrieval function that does \code{SELECT * FROM table}.
|
||||
using a check function that does \verb{SELECT MAX(timestamp) FROM table} and
|
||||
a value retrieval function that does \verb{SELECT * FROM table}.
|
||||
|
||||
The \code{intervalMillis}, \code{checkFunc}, and \code{valueFunc} functions
|
||||
will be executed in a reactive context; therefore, they may read reactive
|
||||
|
||||
@@ -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]{key_missing}}, \code{\link[fastmap]{is.key_missing}}}
|
||||
\item{fastmap}{\code{\link[fastmap]{is.key_missing}}, \code{\link[fastmap]{key_missing}}}
|
||||
}}
|
||||
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
% 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()}}
|
||||
}
|
||||
@@ -4,9 +4,15 @@
|
||||
\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.}
|
||||
|
||||
@@ -4,9 +4,16 @@
|
||||
\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.}
|
||||
|
||||
@@ -4,8 +4,13 @@
|
||||
\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.}
|
||||
|
||||
@@ -4,9 +4,17 @@
|
||||
\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.}
|
||||
|
||||
@@ -4,8 +4,13 @@
|
||||
\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
|
||||
@@ -16,7 +21,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 \code{[options][base::options]('width')}.}
|
||||
\item{width}{The value for \verb{[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
|
||||
@@ -58,7 +63,7 @@ multiprintFun <- renderPrint({
|
||||
"bar"
|
||||
})
|
||||
multiprintFun()
|
||||
# '[1] "foo"\\n[1] "bar"'
|
||||
# '[1] "foo"\n[1] "bar"'
|
||||
|
||||
nullFun <- renderPrint({ NULL })
|
||||
nullFun()
|
||||
|
||||
@@ -4,10 +4,23 @@
|
||||
\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
|
||||
@@ -20,7 +33,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.}
|
||||
|
||||
|
||||
@@ -4,8 +4,13 @@
|
||||
\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
|
||||
@@ -54,7 +59,7 @@ multiprintFun <- renderPrint({
|
||||
"bar"
|
||||
})
|
||||
multiprintFun()
|
||||
# '[1] "foo"\\n[1] "bar"'
|
||||
# '[1] "foo"\n[1] "bar"'
|
||||
|
||||
nullFun <- renderPrint({ NULL })
|
||||
nullFun()
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
\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()}},
|
||||
|
||||
@@ -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 \code{www/} directory are automatically made available
|
||||
\item Static files under the \verb{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}.
|
||||
|
||||
@@ -4,11 +4,16 @@
|
||||
\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:
|
||||
|
||||
@@ -4,10 +4,13 @@
|
||||
\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
|
||||
|
||||
@@ -4,8 +4,13 @@
|
||||
\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
|
||||
|
||||
27
man/runTests.Rd
Normal file
27
man/runTests.Rd
Normal file
@@ -0,0 +1,27 @@
|
||||
% 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()}}.
|
||||
}
|
||||
@@ -10,8 +10,14 @@ 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.}
|
||||
|
||||
@@ -5,8 +5,16 @@
|
||||
\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)
|
||||
}
|
||||
@@ -20,7 +28,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 \code{<optgroup>} HTML tag) for the elements in the respective sublist. See
|
||||
the \verb{<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
|
||||
@@ -120,13 +128,20 @@ 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}
|
||||
|
||||
@@ -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 \code{data:} scheme.
|
||||
the browser is able to handle URIs that use the \verb{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. \code{function(input, output, session)}). The session object is an
|
||||
(e.g. \verb{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
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
\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
|
||||
|
||||
@@ -6,8 +6,14 @@
|
||||
\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())
|
||||
|
||||
@@ -15,7 +21,10 @@ shinyAppFile(appFile, options = list())
|
||||
}
|
||||
\arguments{
|
||||
\item{ui}{The UI definition of the app (for example, a call to
|
||||
\code{fluidPage()} with nested controls)}
|
||||
\code{fluidPage()} with nested controls).
|
||||
|
||||
If bookmarking is enabled (see \code{enableBookmarking}), this must be
|
||||
a single argument function that returns the UI definition.}
|
||||
|
||||
\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
|
||||
@@ -37,11 +46,9 @@ 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"}. 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.}
|
||||
\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.}
|
||||
|
||||
\item{appDir}{Path to directory that contains a Shiny app (i.e. a server.R
|
||||
file and either ui.R or www/index.html)}
|
||||
|
||||
@@ -4,8 +4,12 @@
|
||||
\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.}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user