mirror of
https://github.com/rstudio/shiny.git
synced 2026-01-11 07:58:11 -05:00
Compare commits
132 Commits
fix-factor
...
basicPage
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
561625b270 | ||
|
|
2e0221ecfd | ||
|
|
aeded79544 | ||
|
|
c0a7958e77 | ||
|
|
431b194ec2 | ||
|
|
29d24d7e08 | ||
|
|
3b04c642ae | ||
|
|
609fc5b0c0 | ||
|
|
2a8c79b577 | ||
|
|
043316e40f | ||
|
|
c9d8b987d4 | ||
|
|
33c5a5c665 | ||
|
|
29c90ba163 | ||
|
|
8c19450b10 | ||
|
|
89c97458c4 | ||
|
|
02be516902 | ||
|
|
47ada300ea | ||
|
|
6f9c621774 | ||
|
|
0310fe3b68 | ||
|
|
7144a6e4b7 | ||
|
|
1c8071a96f | ||
|
|
ff5377da9e | ||
|
|
7aee84eb05 | ||
|
|
769c32fd38 | ||
|
|
d05b89cfb3 | ||
|
|
f1f18a2334 | ||
|
|
afc556f801 | ||
|
|
7f240839fc | ||
|
|
8d0a6274cb | ||
|
|
91cab10ff8 | ||
|
|
5828ea7426 | ||
|
|
80ba147168 | ||
|
|
f85479ba11 | ||
|
|
a23c5f151f | ||
|
|
cab3601474 | ||
|
|
cf330fcd58 | ||
|
|
eb0162dccf | ||
|
|
a415aed7e6 | ||
|
|
9f6014dc0b | ||
|
|
21b0d38b57 | ||
|
|
1ec7f22b5f | ||
|
|
346c5e4a4c | ||
|
|
c9a0f0a713 | ||
|
|
8bbc38dc8a | ||
|
|
96494a22f9 | ||
|
|
0813789e2a | ||
|
|
98ca820ab1 | ||
|
|
81ca9d9f29 | ||
|
|
16fe0019f9 | ||
|
|
5fa650ab75 | ||
|
|
564c2a0f16 | ||
|
|
99ac85f06a | ||
|
|
fc30ad0935 | ||
|
|
aadf2eb609 | ||
|
|
68f778e423 | ||
|
|
0066cff652 | ||
|
|
f872a0c80a | ||
|
|
d9478142b1 | ||
|
|
5eced59961 | ||
|
|
3e1862cd51 | ||
|
|
7271609850 | ||
|
|
f24337bb3b | ||
|
|
6167247ea2 | ||
|
|
0332e52501 | ||
|
|
0c23f78ab7 | ||
|
|
7624449644 | ||
|
|
97309e8c4c | ||
|
|
a1e78214db | ||
|
|
1a57b3296b | ||
|
|
7c10fc3514 | ||
|
|
494ef42aa8 | ||
|
|
8a54d216c6 | ||
|
|
896a20d76d | ||
|
|
a26510b02f | ||
|
|
1465f1d237 | ||
|
|
21b18d107a | ||
|
|
cc2173c587 | ||
|
|
71fe821ae9 | ||
|
|
3ffab69ad6 | ||
|
|
58a662bd35 | ||
|
|
eb55c256c7 | ||
|
|
b07e553b9e | ||
|
|
2d61709de3 | ||
|
|
1352e1d92d | ||
|
|
b595c3b902 | ||
|
|
76efb01c4c | ||
|
|
0078945b79 | ||
|
|
70d8ef0b8e | ||
|
|
9a1f7cba68 | ||
|
|
39e14acffe | ||
|
|
a6149390a0 | ||
|
|
33cdc75810 | ||
|
|
13f229089d | ||
|
|
2dbb0fca85 | ||
|
|
c7a8a4e30f | ||
|
|
dc6f1a0c10 | ||
|
|
178872d651 | ||
|
|
e3c15493a2 | ||
|
|
3f22e5da2d | ||
|
|
39ee4513c6 | ||
|
|
598898f0a1 | ||
|
|
052e783638 | ||
|
|
d2deda238a | ||
|
|
7317a8304f | ||
|
|
5ea9d70fb4 | ||
|
|
a73e0998bc | ||
|
|
51befe3e27 | ||
|
|
37569a291b | ||
|
|
7fe973145d | ||
|
|
da3fc276fd | ||
|
|
4c0af8b1c0 | ||
|
|
f65f7b2f1b | ||
|
|
33c86ed6a7 | ||
|
|
545b6c1247 | ||
|
|
1b0e37f371 | ||
|
|
97e00721e9 | ||
|
|
3c43301edb | ||
|
|
51cbb67a96 | ||
|
|
2e2bd80416 | ||
|
|
86389ff7a3 | ||
|
|
c2dfea18c4 | ||
|
|
4be6bbc681 | ||
|
|
cfc0ff9cc7 | ||
|
|
b4c6ba6962 | ||
|
|
dc3ed2f79b | ||
|
|
5d95c7a9cb | ||
|
|
6821ca6238 | ||
|
|
167dc0a259 | ||
|
|
fa9fa68693 | ||
|
|
7caeb60c47 | ||
|
|
e3aba1b5ff | ||
|
|
a6dade846e |
@@ -25,3 +25,6 @@ notifications:
|
||||
email:
|
||||
on_success: change
|
||||
on_failure: change
|
||||
slack:
|
||||
secure: QoM0+hliVC4l2HYv126AkljG/uFvgwayW9IpuB5QNqjSukM122MhMDL7ZuMB9a2vWP24juzOTXiNIymgEspfnvvAMnZwYRBNWkuot2m8HIR2B9UjQLiztFnN1EAT+P+thz8Qax9TV2SOfXb2S2ZOeZmRTVkJctxkL8heAZadIC4=
|
||||
on_pull_requests: false
|
||||
|
||||
10
DESCRIPTION
10
DESCRIPTION
@@ -65,12 +65,12 @@ Depends:
|
||||
Imports:
|
||||
utils,
|
||||
grDevices,
|
||||
httpuv (>= 1.5.0),
|
||||
httpuv (>= 1.5.1.9002),
|
||||
mime (>= 0.3),
|
||||
jsonlite (>= 0.9.16),
|
||||
xtable,
|
||||
digest,
|
||||
htmltools (>= 0.3.6),
|
||||
htmltools (>= 0.3.6.9004),
|
||||
R6 (>= 2.0),
|
||||
sourcetools,
|
||||
later (>= 0.7.2),
|
||||
@@ -78,7 +78,7 @@ Imports:
|
||||
tools,
|
||||
crayon,
|
||||
rlang (>= 0.4.0),
|
||||
fastmap (>= 0.0.0.9001)
|
||||
fastmap (>= 1.0.0)
|
||||
Suggests:
|
||||
datasets,
|
||||
Cairo (>= 1.5-5),
|
||||
@@ -89,6 +89,9 @@ Suggests:
|
||||
ggplot2,
|
||||
reactlog (>= 1.0.0),
|
||||
magrittr
|
||||
Remotes:
|
||||
rstudio/htmltools,
|
||||
rstudio/httpuv
|
||||
URL: http://shiny.rstudio.com
|
||||
BugReports: https://github.com/rstudio/shiny/issues
|
||||
Collate:
|
||||
@@ -96,6 +99,7 @@ Collate:
|
||||
'bookmark-state-local.R'
|
||||
'stack.R'
|
||||
'bookmark-state.R'
|
||||
'bootstrap-deprecated.R'
|
||||
'bootstrap-layout.R'
|
||||
'globals.R'
|
||||
'conditions.R'
|
||||
|
||||
4
LICENSE
4
LICENSE
@@ -25,7 +25,7 @@ these components are included below):
|
||||
jQuery license and license for included components from jQuery UI
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright jQuery Foundation and other contributors, https://jquery.org/
|
||||
Copyright JS Foundation and other contributors, https://js.foundation/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
@@ -51,7 +51,7 @@ Bootstrap License
|
||||
----------------------------------------------------------------------
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2011-2014 Twitter, Inc
|
||||
Copyright (c) 2011-2019 Twitter, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
13
NAMESPACE
13
NAMESPACE
@@ -26,7 +26,9 @@ S3method(format,reactiveExpr)
|
||||
S3method(format,reactiveVal)
|
||||
S3method(names,reactivevalues)
|
||||
S3method(print,reactive)
|
||||
S3method(print,reactivevalues)
|
||||
S3method(print,shiny.appobj)
|
||||
S3method(print,shiny.render.function)
|
||||
S3method(str,reactivevalues)
|
||||
export("conditionStackTrace<-")
|
||||
export(..stacktraceoff..)
|
||||
@@ -132,12 +134,7 @@ export(isRunning)
|
||||
export(isTruthy)
|
||||
export(isolate)
|
||||
export(key_missing)
|
||||
export(knit_print.html)
|
||||
export(knit_print.reactive)
|
||||
export(knit_print.shiny.appobj)
|
||||
export(knit_print.shiny.render.function)
|
||||
export(knit_print.shiny.tag)
|
||||
export(knit_print.shiny.tag.list)
|
||||
export(loadSupport)
|
||||
export(mainPanel)
|
||||
export(makeReactiveBinding)
|
||||
export(markRenderFunction)
|
||||
@@ -195,6 +192,7 @@ export(registerInputHandler)
|
||||
export(removeInputHandler)
|
||||
export(removeModal)
|
||||
export(removeNotification)
|
||||
export(removeResourcePath)
|
||||
export(removeTab)
|
||||
export(removeUI)
|
||||
export(renderCachedPlot)
|
||||
@@ -207,6 +205,7 @@ export(renderText)
|
||||
export(renderUI)
|
||||
export(repeatable)
|
||||
export(req)
|
||||
export(resourcePaths)
|
||||
export(restoreInput)
|
||||
export(runApp)
|
||||
export(runExample)
|
||||
@@ -253,6 +252,8 @@ export(tag)
|
||||
export(tagAppendAttributes)
|
||||
export(tagAppendChild)
|
||||
export(tagAppendChildren)
|
||||
export(tagGetAttribute)
|
||||
export(tagHasAttribute)
|
||||
export(tagList)
|
||||
export(tagSetChildren)
|
||||
export(tags)
|
||||
|
||||
26
NEWS.md
26
NEWS.md
@@ -9,18 +9,33 @@ shiny 1.3.2.9001
|
||||
|
||||
* Resolved [#2402](https://github.com/rstudio/shiny/issues/2402): An informative warning is now thrown for mis-specified (date) strings in `dateInput()`, `updateDateInput()`, `dateRangeInput()`, and `updateDateRangeInput()`. ([#2403](https://github.com/rstudio/shiny/pull/2403))
|
||||
|
||||
* If the `shiny.autoload.r` option is set to `TRUE`, all files ending in `.r` or `.R` contained in a directory named `R/` adjacent to your application are sourced when your app is started. This will become the default Shiny behavior in a future release ([#2547](https://github.com/rstudio/shiny/pull/2547))
|
||||
|
||||
|
||||
* Resolved [#2442](https://github.com/rstudio/shiny/issues/2442): The `shiny:inputchanged` JavaScript event now triggers on the related input element instead of `document`. Existing event listeners bound to `document` will still detect the event due to event bubbling. ([#2446](https://github.com/rstudio/shiny/pull/2446))
|
||||
|
||||
* Fixed [#1393](https://github.com/rstudio/shiny/issues/1393), [#2223](https://github.com/rstudio/shiny/issues/2223): For plots with any interactions enabled, the image is no longer draggable. ([#2460](https://github.com/rstudio/shiny/pull/2460))
|
||||
|
||||
* Partially resolved [#2423](https://github.com/rstudio/shiny/issues/2423): Reactivity in Shiny leaked some memory, because R can leak memory whenever a new symbols is interned, which happens whenever a new name/key is used in an environment. R now uses the fastmap package, which avoids this problem. ([#2429](https://github.com/rstudio/shiny/pull/2429))
|
||||
|
||||
* Fixed [#2267](https://github.com/rstudio/shiny/issues/2267): Fixed a memory leak with `invalidateLater`. ([#2555](https://github.com/rstudio/shiny/pull/2555))
|
||||
|
||||
* Fixed [#1548](https://github.com/rstudio/shiny/issues/1548): The `reactivePoll` function leaked an observer; that is the observer would continue to exist even if the `reactivePoll` object was no longer accessible. [#2522](https://github.com/rstudio/shiny/pull/2522)
|
||||
|
||||
* Resolved [#2469](https://github.com/rstudio/shiny/issues/2469): `renderText` now takes a `sep` argument that is passed to `cat`. ([#2497](https://github.com/rstudio/shiny/pull/2497))
|
||||
|
||||
* Added `resourcePaths()` and `removeResourcePaths()` functions. ([#2459](https://github.com/rstudio/shiny/pull/2459))
|
||||
|
||||
* Resolved [#2515](https://github.com/rstudio/shiny/issues/2515): `selectInput()` now deals appropriately with named factors. ([#2524](https://github.com/rstudio/shiny/pull/2524))
|
||||
|
||||
* Resolved [#2433](https://github.com/rstudio/shiny/issues/2433): An informative warning is now thrown if subdirectories of the app's `www/` directory are masked by other resource prefixes and/or the same resource prefix is mapped to different local file paths. ([#2434](https://github.com/rstudio/shiny/pull/2434))
|
||||
|
||||
* Resolved [#2471](https://github.com/rstudio/shiny/issues/2471): Large file uploads to a Windows computer were slow. ([#2579](https://github.com/rstudio/shiny/pull/2579))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* Fixed [#2116](https://github.com/rstudio/shiny/issues/2116): Fixed an issue where dynamic tabs could not be added when on a hosted platform. ([#2545](https://github.com/rstudio/shiny/pull/2545))
|
||||
|
||||
* Fixed [#2387](https://github.com/rstudio/shiny/issues/2387): Updating a `sliderInput()`'s type from numeric to date no longer changes the rate policy from debounced to immediate. More generally, updating an input binding with a new type should (no longer) incorrectly alter the input rate policy. ([#2404](https://github.com/rstudio/shiny/pull/2404))
|
||||
|
||||
* Fixed [#868](https://github.com/rstudio/shiny/issues/868): If an input is initialized with a `NULL` label, it can now be updated with a string. Moreover, if an input label is initialized with a string, it can now be removed by updating with `label=character(0)` (similar to how `choices` and `selected` can be cleared in `updateSelectInput()`). ([#2406](https://github.com/rstudio/shiny/pull/2406))
|
||||
@@ -31,10 +46,19 @@ shiny 1.3.2.9001
|
||||
|
||||
* Fixed [#2233](https://github.com/rstudio/shiny/issues/2233): `verbatimTextOutput()` produced wrapped text on Safari, but the text should not be wrapped. ([#2353](https://github.com/rstudio/shiny/pull/2353))
|
||||
|
||||
* Fixed [#2335](https://github.com/rstudio/shiny/issues/2335): When `dateInput()`'s `value` was unspecified, and `max` and/or `min` was set to `Sys.Date()`, the value was not being set properly. ([#2526](https://github.com/rstudio/shiny/pull/2526))
|
||||
|
||||
* Fixed [#2591](https://github.com/rstudio/shiny/issues/2591): Providing malformed date-strings to `min` or `max` no longer results in JS errors for `dateInput()` and `dateRangeInput()`. ([#2592](https://github.com/rstudio/shiny/pull/2592))
|
||||
|
||||
* Fixed [rstudio/reactlog#36](https://github.com/rstudio/reactlog/issues/36): Changes to reactive values not displaying accurately in reactlog. ([#2424](https://github.com/rstudio/shiny/pull/2424))
|
||||
|
||||
* Fixed [#2329](https://github.com/rstudio/shiny/issues/2329), [#1817](https://github.com/rstudio/shiny/issues/1817): These bugs were reported as fixed in Shiny 1.3.0 but were not actually fixed because some JavaScript changes were accidentally not included in the release. The fix resolves issues that occur when `withProgressBar()` or bookmarking are combined with the [networkD3](https://christophergandrud.github.io/networkD3/) package's Sankey plot.
|
||||
|
||||
### Library updates
|
||||
|
||||
* Resolved [#2554](https://github.com/rstudio/shiny/issues/2554): Upgraded bootstrap to v3.4.1 and jQuery to v3.4.1. ([#2557](https://github.com/rstudio/shiny/pull/2557))
|
||||
|
||||
|
||||
shiny 1.3.2
|
||||
===========
|
||||
|
||||
@@ -132,6 +156,8 @@ This release features plot caching, an important new tool for improving performa
|
||||
|
||||
* Fixed [#2138](https://github.com/rstudio/shiny/issues/2138): Inputs that are part of a `renderUI` were no longer restoring correctly from bookmarked state. [#2139](https://github.com/rstudio/shiny/pull/2139)
|
||||
|
||||
* The `knit_print` methods from htmltools are no longer imported into shiny and then exported. Also, shiny's `knit_print` methods are no longer exported. [#2166](https://github.com/rstudio/shiny/pull/2166)
|
||||
|
||||
* Fixed [#2093](https://github.com/rstudio/shiny/issues/2093): Make sure bookmark scope directory does not exist before trying to create it. [#2168](https://github.com/rstudio/shiny/pull/2168)
|
||||
|
||||
* Fixed [#2177](https://github.com/rstudio/shiny/issues/2177): The session name is now being recorded when exiting a context. Multiple sessions can now view their respective reactlogs. [#2180](https://github.com/rstudio/shiny/pull/2180)
|
||||
|
||||
115
R/app.R
115
R/app.R
@@ -14,7 +14,9 @@
|
||||
#'
|
||||
#' @param ui The UI definition of the app (for example, a call to
|
||||
#' `fluidPage()` with nested controls)
|
||||
#' @param server A server function
|
||||
#' @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.
|
||||
#' @param onStart A function that will be called before the app is actually run.
|
||||
#' This is only needed for `shinyAppObj`, since in the `shinyAppDir`
|
||||
#' case, a `global.R` file can be used for this purpose.
|
||||
@@ -68,10 +70,10 @@
|
||||
#' runApp(app)
|
||||
#' }
|
||||
#' @export
|
||||
shinyApp <- function(ui=NULL, server=NULL, onStart=NULL, options=list(),
|
||||
shinyApp <- function(ui, server, onStart=NULL, options=list(),
|
||||
uiPattern="/", enableBookmarking=NULL) {
|
||||
if (is.null(server)) {
|
||||
stop("`server` missing from shinyApp")
|
||||
if (!is.function(server)) {
|
||||
stop("`server` must be a function", call. = FALSE)
|
||||
}
|
||||
|
||||
# Ensure that the entire path is a match
|
||||
@@ -139,10 +141,23 @@ shinyAppFile <- function(appFile, options=list()) {
|
||||
|
||||
# This reads in an app dir in the case that there's a server.R (and ui.R/www)
|
||||
# present, and returns a shiny.appobj.
|
||||
# appDir must be a normalized (absolute) path, not a relative one
|
||||
shinyAppDir_serverR <- function(appDir, options=list()) {
|
||||
# Most of the complexity here comes from needing to hot-reload if the .R files
|
||||
# change on disk, or are created, or are removed.
|
||||
|
||||
# In an upcoming version of shiny, this option will go away and the new behavior will be used.
|
||||
if (getOption("shiny.autoload.r", FALSE)) {
|
||||
# new behavior
|
||||
|
||||
# Create a child env which contains all the helpers and will be the shared parent
|
||||
# of the ui.R and server.R load.
|
||||
sharedEnv <- new.env(parent = globalenv())
|
||||
} else {
|
||||
# old behavior, default
|
||||
sharedEnv <- globalenv()
|
||||
}
|
||||
|
||||
# uiHandlerSource is a function that returns an HTTP handler for serving up
|
||||
# ui.R as a webpage. The "cachedFuncWithFile" call makes sure that the closure
|
||||
# we're creating here only gets executed when ui.R's contents change.
|
||||
@@ -153,7 +168,7 @@ shinyAppDir_serverR <- function(appDir, options=list()) {
|
||||
# If not, then take the last expression that's returned from ui.R.
|
||||
.globals$ui <- NULL
|
||||
on.exit(.globals$ui <- NULL, add = FALSE)
|
||||
ui <- sourceUTF8(uiR, envir = new.env(parent = globalenv()))
|
||||
ui <- sourceUTF8(uiR, envir = new.env(parent = sharedEnv))
|
||||
if (!is.null(.globals$ui)) {
|
||||
ui <- .globals$ui[[1]]
|
||||
}
|
||||
@@ -183,7 +198,7 @@ shinyAppDir_serverR <- function(appDir, options=list()) {
|
||||
# server.R.
|
||||
.globals$server <- NULL
|
||||
on.exit(.globals$server <- NULL, add = TRUE)
|
||||
result <- sourceUTF8(serverR, envir = new.env(parent = globalenv()))
|
||||
result <- sourceUTF8(serverR, envir = new.env(parent = sharedEnv))
|
||||
if (!is.null(.globals$server)) {
|
||||
result <- .globals$server[[1]]
|
||||
}
|
||||
@@ -214,8 +229,13 @@ shinyAppDir_serverR <- function(appDir, options=list()) {
|
||||
oldwd <<- getwd()
|
||||
setwd(appDir)
|
||||
monitorHandle <<- initAutoReloadMonitor(appDir)
|
||||
if (file.exists(file.path.ci(appDir, "global.R")))
|
||||
sourceUTF8(file.path.ci(appDir, "global.R"))
|
||||
# TODO: we should support hot reloading on global.R and R/*.R changes.
|
||||
if (getOption("shiny.autoload.r", FALSE)) {
|
||||
loadSupport(appDir, renv=sharedEnv, globalrenv=globalenv())
|
||||
} else {
|
||||
if (file.exists(file.path.ci(appDir, "global.R")))
|
||||
sourceUTF8(file.path.ci(appDir, "global.R"))
|
||||
}
|
||||
}
|
||||
onStop <- function() {
|
||||
setwd(oldwd)
|
||||
@@ -288,18 +308,66 @@ initAutoReloadMonitor <- function(dir) {
|
||||
obs$destroy
|
||||
}
|
||||
|
||||
#' Load an app's supporting R files
|
||||
#'
|
||||
#' Loads all of the supporting R files of a Shiny application. Specifically,
|
||||
#' this function loads any top-level supporting `.R` files in the `R/` directory
|
||||
#' adjacent to the `app.R`/`server.R`/`ui.R` files.
|
||||
#'
|
||||
#' At the moment, this function is "opt-in" and only called if the option
|
||||
#' `shiny.autoload.r` is set to `TRUE`.
|
||||
#'
|
||||
#' @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.
|
||||
#' @param appDir The application directory
|
||||
#' @param renv The environmeny in which the files in the `R/` directory should
|
||||
#' be evaluated.
|
||||
#' @param globalrenv The environment in which `global.R` should be evaluated. If
|
||||
#' `NULL`, `global.R` will not be evaluated at all.
|
||||
#' @export
|
||||
loadSupport <- function(appDir, renv=new.env(parent=globalenv()), globalrenv=globalenv()){
|
||||
if (!is.null(globalrenv)){
|
||||
# Evaluate global.R, if it exists.
|
||||
if (file.exists(file.path.ci(appDir, "global.R"))){
|
||||
sourceUTF8(file.path.ci(appDir, "global.R"), envir=globalrenv)
|
||||
}
|
||||
}
|
||||
|
||||
helpersDir <- file.path(appDir, "R")
|
||||
helpers <- list.files(helpersDir, pattern="\\.[rR]$", recursive=FALSE, full.names=TRUE)
|
||||
|
||||
lapply(helpers, sourceUTF8, envir=renv)
|
||||
|
||||
invisible(renv)
|
||||
}
|
||||
|
||||
# This reads in an app dir for a single-file application (e.g. app.R), and
|
||||
# returns a shiny.appobj.
|
||||
# appDir must be a normalized (absolute) path, not a relative one
|
||||
shinyAppDir_appR <- function(fileName, appDir, options=list())
|
||||
{
|
||||
fullpath <- file.path.ci(appDir, fileName)
|
||||
|
||||
# In an upcoming version of shiny, this option will go away and the new behavior will be used.
|
||||
if (getOption("shiny.autoload.r", FALSE)) {
|
||||
# new behavior
|
||||
|
||||
# Create a child env which contains all the helpers and will be the shared parent
|
||||
# of the ui.R and server.R load.
|
||||
sharedEnv <- new.env(parent = globalenv())
|
||||
} else {
|
||||
# old behavior, default
|
||||
sharedEnv <- globalenv()
|
||||
}
|
||||
|
||||
|
||||
# This sources app.R and caches the content. When appObj() is called but
|
||||
# app.R hasn't changed, it won't re-source the file. But if called and
|
||||
# app.R has changed, it'll re-source the file and return the result.
|
||||
appObj <- cachedFuncWithFile(appDir, fileName, case.sensitive = FALSE,
|
||||
function(appR) {
|
||||
result <- sourceUTF8(fullpath, envir = new.env(parent = globalenv()))
|
||||
result <- sourceUTF8(fullpath, envir = new.env(parent = sharedEnv))
|
||||
|
||||
if (!is.shiny.appobj(result))
|
||||
stop("app.R did not return a shiny.appobj object.")
|
||||
@@ -342,6 +410,10 @@ shinyAppDir_appR <- function(fileName, appDir, options=list())
|
||||
onStart <- function() {
|
||||
oldwd <<- getwd()
|
||||
setwd(appDir)
|
||||
# TODO: we should support hot reloading on R/*.R changes.
|
||||
if (getOption("shiny.autoload.r", FALSE)) {
|
||||
loadSupport(appDir, renv=sharedEnv, globalrenv=NULL)
|
||||
}
|
||||
monitorHandle <<- initAutoReloadMonitor(appDir)
|
||||
if (!is.null(appObj()$onStart)) appObj()$onStart()
|
||||
}
|
||||
@@ -376,26 +448,34 @@ shinyAppDir_appR <- function(fileName, appDir, options=list())
|
||||
}
|
||||
|
||||
|
||||
#' @rdname shinyApp
|
||||
#' Shiny App object
|
||||
#'
|
||||
#' Internal methods for the `shiny.appobj` S3 class.
|
||||
#'
|
||||
#' @keywords internal
|
||||
#' @name shiny.appobj
|
||||
NULL
|
||||
|
||||
#' @rdname shiny.appobj
|
||||
#' @param x Object to convert to a Shiny app.
|
||||
#' @export
|
||||
as.shiny.appobj <- function(x) {
|
||||
UseMethod("as.shiny.appobj", x)
|
||||
}
|
||||
|
||||
#' @rdname shinyApp
|
||||
#' @rdname shiny.appobj
|
||||
#' @export
|
||||
as.shiny.appobj.shiny.appobj <- function(x) {
|
||||
x
|
||||
}
|
||||
|
||||
#' @rdname shinyApp
|
||||
#' @rdname shiny.appobj
|
||||
#' @export
|
||||
as.shiny.appobj.list <- function(x) {
|
||||
shinyApp(ui = x$ui, server = x$server)
|
||||
}
|
||||
|
||||
#' @rdname shinyApp
|
||||
#' @rdname shiny.appobj
|
||||
#' @export
|
||||
as.shiny.appobj.character <- function(x) {
|
||||
if (identical(tolower(tools::file_ext(x)), "r"))
|
||||
@@ -404,13 +484,13 @@ as.shiny.appobj.character <- function(x) {
|
||||
shinyAppDir(x)
|
||||
}
|
||||
|
||||
#' @rdname shinyApp
|
||||
#' @rdname shiny.appobj
|
||||
#' @export
|
||||
is.shiny.appobj <- function(x) {
|
||||
inherits(x, "shiny.appobj")
|
||||
}
|
||||
|
||||
#' @rdname shinyApp
|
||||
#' @rdname shiny.appobj
|
||||
#' @param ... Additional parameters to be passed to print.
|
||||
#' @export
|
||||
print.shiny.appobj <- function(x, ...) {
|
||||
@@ -425,7 +505,7 @@ print.shiny.appobj <- function(x, ...) {
|
||||
do.call("runApp", args)
|
||||
}
|
||||
|
||||
#' @rdname shinyApp
|
||||
#' @rdname shiny.appobj
|
||||
#' @method as.tags shiny.appobj
|
||||
#' @export
|
||||
as.tags.shiny.appobj <- function(x, ...) {
|
||||
@@ -479,7 +559,6 @@ shiny_rmd_warning <- function() {
|
||||
}
|
||||
|
||||
#' @rdname knitr_methods
|
||||
#' @export
|
||||
knit_print.shiny.appobj <- function(x, ...) {
|
||||
opts <- x$options %OR% list()
|
||||
width <- if (is.null(opts$width)) "100%" else opts$width
|
||||
@@ -516,7 +595,6 @@ knit_print.shiny.appobj <- function(x, ...) {
|
||||
# calling output$value <- renderFoo(...) and fooOutput().
|
||||
#' @rdname knitr_methods
|
||||
#' @param inline Whether the object is printed inline.
|
||||
#' @export
|
||||
knit_print.shiny.render.function <- function(x, ..., inline = FALSE) {
|
||||
x <- htmltools::as.tags(x, inline = inline)
|
||||
output <- knitr::knit_print(tagList(x))
|
||||
@@ -529,7 +607,6 @@ knit_print.shiny.render.function <- function(x, ..., inline = FALSE) {
|
||||
# Lets us drop reactive expressions directly into a knitr chunk and have the
|
||||
# value printed out! Nice for teaching if nothing else.
|
||||
#' @rdname knitr_methods
|
||||
#' @export
|
||||
knit_print.reactive <- function(x, ..., inline = FALSE) {
|
||||
renderFunc <- if (inline) renderText else renderPrint
|
||||
knitr::knit_print(renderFunc({
|
||||
|
||||
91
R/bootstrap-deprecated.R
Normal file
91
R/bootstrap-deprecated.R
Normal file
@@ -0,0 +1,91 @@
|
||||
#' Create a page with a sidebar
|
||||
#'
|
||||
#' **DEPRECATED**: use [fluidPage()] and [sidebarLayout()] instead.
|
||||
#'
|
||||
#' @param headerPanel The [headerPanel] with the application title
|
||||
#' @param sidebarPanel The [sidebarPanel] containing input controls
|
||||
#' @param mainPanel The [mainPanel] containing outputs
|
||||
#' @keywords internal
|
||||
#' @return A UI defintion that can be passed to the [shinyUI] function
|
||||
#' @export
|
||||
pageWithSidebar <- function(headerPanel,
|
||||
sidebarPanel,
|
||||
mainPanel) {
|
||||
|
||||
bootstrapPage(
|
||||
# basic application container divs
|
||||
div(
|
||||
class="container-fluid",
|
||||
div(class="row",
|
||||
headerPanel
|
||||
),
|
||||
div(class="row",
|
||||
sidebarPanel,
|
||||
mainPanel
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
#' Create a header panel
|
||||
#'
|
||||
#' **DEPRECATED**: use [titlePanel()] instead.
|
||||
#'
|
||||
#' @param title An application title to display
|
||||
#' @param windowTitle The title that should be displayed by the browser window.
|
||||
#' Useful if `title` is not a string.
|
||||
#' @return A headerPanel that can be passed to [pageWithSidebar]
|
||||
#' @keywords internal
|
||||
#' @export
|
||||
headerPanel <- function(title, windowTitle=title) {
|
||||
tagList(
|
||||
tags$head(tags$title(windowTitle)),
|
||||
div(class="col-sm-12",
|
||||
h1(title)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
#' Create a Bootstrap page
|
||||
#'
|
||||
#' **DEPRECATED**: use [fluidPage()] instead.
|
||||
#'
|
||||
#' @param ... The contents of the document body.
|
||||
#' @param title The browser window title (defaults to the host URL of the page)
|
||||
#' @param responsive This option is deprecated; it is no longer optional with
|
||||
#' Bootstrap 3.
|
||||
#' @param theme Alternative Bootstrap stylesheet (normally a css file within the
|
||||
#' www directory, e.g. `www/bootstrap.css`)
|
||||
#'
|
||||
#' @return A UI defintion that can be passed to the [shinyUI] function.
|
||||
#'
|
||||
#' @keywords internal
|
||||
#' @seealso [fluidPage()], [fixedPage()]
|
||||
#' @export
|
||||
bootstrapPage <- function(..., title = NULL, responsive = NULL, theme = NULL) {
|
||||
|
||||
if (!is.null(responsive)) {
|
||||
shinyDeprecated("The 'responsive' argument is no longer used with Bootstrap 3.")
|
||||
}
|
||||
|
||||
attachDependencies(
|
||||
tagList(
|
||||
if (!is.null(title)) tags$head(tags$title(title)),
|
||||
if (!is.null(theme)) {
|
||||
tags$head(tags$link(rel="stylesheet", type="text/css", href = theme))
|
||||
},
|
||||
|
||||
# remainder of tags passed to the function
|
||||
list(...)
|
||||
),
|
||||
bootstrapLib()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
#' @rdname bootstrapPage
|
||||
#' @export
|
||||
basicPage <- function(...) {
|
||||
bootstrapPage(div(class="container-fluid", list(...)))
|
||||
}
|
||||
@@ -263,16 +263,21 @@ titlePanel <- function(title, windowTitle=title) {
|
||||
|
||||
#' Layout a sidebar and main area
|
||||
#'
|
||||
#' Create a layout with a sidebar and main area. The sidebar is displayed with a
|
||||
#' distinct background color and typically contains input controls. The main
|
||||
#' Create a layout (`sidebarLayout()`) with a sidebar (`sidebarPanel()`) and
|
||||
#' main area (`mainPanel()`). The sidebar is displayed with a distinct
|
||||
#' background color and typically contains input controls. The main
|
||||
#' area occupies 2/3 of the horizontal width and typically contains outputs.
|
||||
#'
|
||||
#' @param sidebarPanel The [sidebarPanel] containing input controls
|
||||
#' @param mainPanel The [mainPanel] containing outputs
|
||||
#' @param sidebarPanel The `sidebarPanel()` containing input controls.
|
||||
#' @param mainPanel The `mainPanel()` containing outputs.
|
||||
#' @param position The position of the sidebar relative to the main area ("left"
|
||||
#' or "right")
|
||||
#' or "right").
|
||||
#' @param fluid `TRUE` to use fluid layout; `FALSE` to use fixed
|
||||
#' layout.
|
||||
#' @param width The width of the sidebar and main panel. By default, the
|
||||
#' sidebar takes up 1/3 of the width, and the main panel 2/3. The total
|
||||
#' width must be 12 or less.
|
||||
#' @param ... Output elements to include in the sidebar/main panel.
|
||||
#'
|
||||
#' @examples
|
||||
#' ## Only run examples in interactive R sessions
|
||||
@@ -337,6 +342,24 @@ sidebarLayout <- function(sidebarPanel,
|
||||
fixedRow(firstPanel, secondPanel)
|
||||
}
|
||||
|
||||
#' @export
|
||||
#' @rdname sidebarLayout
|
||||
sidebarPanel <- function(..., width = 4) {
|
||||
div(class=paste0("col-sm-", width),
|
||||
tags$form(class="well",
|
||||
...
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
#' @export
|
||||
#' @rdname sidebarLayout
|
||||
mainPanel <- function(..., width = 8) {
|
||||
div(class=paste0("col-sm-", width),
|
||||
...
|
||||
)
|
||||
}
|
||||
|
||||
#' Lay out UI elements vertically
|
||||
#'
|
||||
#' Create a container that includes one or more rows of content (each element
|
||||
|
||||
185
R/bootstrap.R
185
R/bootstrap.R
@@ -1,51 +1,6 @@
|
||||
#' @include utils.R
|
||||
NULL
|
||||
|
||||
#' Create a Bootstrap page
|
||||
#'
|
||||
#' Create a Shiny UI page that loads the CSS and JavaScript for
|
||||
#' [Bootstrap](http://getbootstrap.com/), and has no content in the page
|
||||
#' body (other than what you provide).
|
||||
#'
|
||||
#' This function is primarily intended for users who are proficient in HTML/CSS,
|
||||
#' and know how to lay out pages in Bootstrap. Most applications should use
|
||||
#' [fluidPage()] along with layout functions like
|
||||
#' [fluidRow()] and [sidebarLayout()].
|
||||
#'
|
||||
#' @param ... The contents of the document body.
|
||||
#' @param title The browser window title (defaults to the host URL of the page)
|
||||
#' @param responsive This option is deprecated; it is no longer optional with
|
||||
#' Bootstrap 3.
|
||||
#' @param theme Alternative Bootstrap stylesheet (normally a css file within the
|
||||
#' www directory, e.g. `www/bootstrap.css`)
|
||||
#'
|
||||
#' @return A UI defintion that can be passed to the [shinyUI] function.
|
||||
#'
|
||||
#' @note The `basicPage` function is deprecated, you should use the
|
||||
#' [fluidPage()] function instead.
|
||||
#'
|
||||
#' @seealso [fluidPage()], [fixedPage()]
|
||||
#' @export
|
||||
bootstrapPage <- function(..., title = NULL, responsive = NULL, theme = NULL) {
|
||||
|
||||
if (!is.null(responsive)) {
|
||||
shinyDeprecated("The 'responsive' argument is no longer used with Bootstrap 3.")
|
||||
}
|
||||
|
||||
attachDependencies(
|
||||
tagList(
|
||||
if (!is.null(title)) tags$head(tags$title(title)),
|
||||
if (!is.null(theme)) {
|
||||
tags$head(tags$link(rel="stylesheet", type="text/css", href = theme))
|
||||
},
|
||||
|
||||
# remainder of tags passed to the function
|
||||
list(...)
|
||||
),
|
||||
bootstrapLib()
|
||||
)
|
||||
}
|
||||
|
||||
#' Bootstrap libraries
|
||||
#'
|
||||
#' This function returns a set of web dependencies necessary for using Bootstrap
|
||||
@@ -60,7 +15,7 @@ bootstrapPage <- function(..., title = NULL, responsive = NULL, theme = NULL) {
|
||||
#' @inheritParams bootstrapPage
|
||||
#' @export
|
||||
bootstrapLib <- function(theme = NULL) {
|
||||
htmlDependency("bootstrap", "3.3.7",
|
||||
htmlDependency("bootstrap", "3.4.1",
|
||||
c(
|
||||
href = "shared/bootstrap",
|
||||
file = system.file("www/shared/bootstrap", package = "shiny")
|
||||
@@ -76,12 +31,6 @@ bootstrapLib <- function(theme = NULL) {
|
||||
)
|
||||
}
|
||||
|
||||
#' @rdname bootstrapPage
|
||||
#' @export
|
||||
basicPage <- function(...) {
|
||||
bootstrapPage(div(class="container-fluid", list(...)))
|
||||
}
|
||||
|
||||
|
||||
#' Create a page that fills the window
|
||||
#'
|
||||
@@ -178,61 +127,6 @@ collapseSizes <- function(padding) {
|
||||
collapse = " ")
|
||||
}
|
||||
|
||||
#' Create a page with a sidebar
|
||||
#'
|
||||
#' Create a Shiny UI that contains a header with the application title, a
|
||||
#' sidebar for input controls, and a main area for output.
|
||||
#'
|
||||
#' @param headerPanel The [headerPanel] with the application title
|
||||
#' @param sidebarPanel The [sidebarPanel] containing input controls
|
||||
#' @param mainPanel The [mainPanel] containing outputs
|
||||
|
||||
#' @return A UI defintion that can be passed to the [shinyUI] function
|
||||
#'
|
||||
#' @note This function is deprecated. You should use [fluidPage()]
|
||||
#' along with [sidebarLayout()] to implement a page with a sidebar.
|
||||
#'
|
||||
#' @examples
|
||||
#' # Define UI
|
||||
#' pageWithSidebar(
|
||||
#'
|
||||
#' # Application title
|
||||
#' headerPanel("Hello Shiny!"),
|
||||
#'
|
||||
#' # Sidebar with a slider input
|
||||
#' sidebarPanel(
|
||||
#' sliderInput("obs",
|
||||
#' "Number of observations:",
|
||||
#' min = 0,
|
||||
#' max = 1000,
|
||||
#' value = 500)
|
||||
#' ),
|
||||
#'
|
||||
#' # Show a plot of the generated distribution
|
||||
#' mainPanel(
|
||||
#' plotOutput("distPlot")
|
||||
#' )
|
||||
#' )
|
||||
#' @export
|
||||
pageWithSidebar <- function(headerPanel,
|
||||
sidebarPanel,
|
||||
mainPanel) {
|
||||
|
||||
bootstrapPage(
|
||||
# basic application container divs
|
||||
div(
|
||||
class="container-fluid",
|
||||
div(class="row",
|
||||
headerPanel
|
||||
),
|
||||
div(class="row",
|
||||
sidebarPanel,
|
||||
mainPanel
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
#' Create a page with a top level navigation bar
|
||||
#'
|
||||
#' Create a page that contains a top level navigation bar that can be used to
|
||||
@@ -408,27 +302,6 @@ navbarMenu <- function(title, ..., menuName = title, icon = NULL) {
|
||||
class = "shiny.navbarmenu")
|
||||
}
|
||||
|
||||
#' Create a header panel
|
||||
#'
|
||||
#' Create a header panel containing an application title.
|
||||
#'
|
||||
#' @param title An application title to display
|
||||
#' @param windowTitle The title that should be displayed by the browser window.
|
||||
#' Useful if `title` is not a string.
|
||||
#' @return A headerPanel that can be passed to [pageWithSidebar]
|
||||
#'
|
||||
#' @examples
|
||||
#' headerPanel("Hello Shiny!")
|
||||
#' @export
|
||||
headerPanel <- function(title, windowTitle=title) {
|
||||
tagList(
|
||||
tags$head(tags$title(windowTitle)),
|
||||
div(class="col-sm-12",
|
||||
h1(title)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
#' Create a well panel
|
||||
#'
|
||||
#' Creates a panel with a slightly inset border and grey background. Equivalent
|
||||
@@ -441,59 +314,6 @@ wellPanel <- function(...) {
|
||||
div(class="well", ...)
|
||||
}
|
||||
|
||||
#' Create a sidebar panel
|
||||
#'
|
||||
#' Create a sidebar panel containing input controls that can in turn be passed
|
||||
#' to [sidebarLayout()].
|
||||
#'
|
||||
#' @param ... UI elements to include on the sidebar
|
||||
#' @param width The width of the sidebar. For fluid layouts this is out of 12
|
||||
#' total units; for fixed layouts it is out of whatever the width of the
|
||||
#' sidebar's parent column is.
|
||||
#' @return A sidebar that can be passed to [sidebarLayout()]
|
||||
#'
|
||||
#' @examples
|
||||
#' # Sidebar with controls to select a dataset and specify
|
||||
#' # the number of observations to view
|
||||
#' sidebarPanel(
|
||||
#' selectInput("dataset", "Choose a dataset:",
|
||||
#' choices = c("rock", "pressure", "cars")),
|
||||
#'
|
||||
#' numericInput("obs", "Observations:", 10)
|
||||
#' )
|
||||
#' @export
|
||||
sidebarPanel <- function(..., width = 4) {
|
||||
div(class=paste0("col-sm-", width),
|
||||
tags$form(class="well",
|
||||
...
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
#' Create a main panel
|
||||
#'
|
||||
#' Create a main panel containing output elements that can in turn be passed to
|
||||
#' [sidebarLayout()].
|
||||
#'
|
||||
#' @param ... Output elements to include in the main panel
|
||||
#' @param width The width of the main panel. For fluid layouts this is out of 12
|
||||
#' total units; for fixed layouts it is out of whatever the width of the main
|
||||
#' panel's parent column is.
|
||||
#' @return A main panel that can be passed to [sidebarLayout()].
|
||||
#'
|
||||
#' @examples
|
||||
#' # Show the caption and plot of the requested variable against mpg
|
||||
#' mainPanel(
|
||||
#' h3(textOutput("caption")),
|
||||
#' plotOutput("mpgPlot")
|
||||
#' )
|
||||
#' @export
|
||||
mainPanel <- function(..., width = 8) {
|
||||
div(class=paste0("col-sm-", width),
|
||||
...
|
||||
)
|
||||
}
|
||||
|
||||
#' Conditional Panel
|
||||
#'
|
||||
#' Creates a panel that is visible or not, depending on the value of a
|
||||
@@ -589,7 +409,8 @@ helpText <- function(...) {
|
||||
|
||||
#' Create a tab panel
|
||||
#'
|
||||
#' Create a tab panel that can be included within a [tabsetPanel()].
|
||||
#' Create a tab panel that can be included within a [tabsetPanel()] or
|
||||
#' a [navbarPage()].
|
||||
#'
|
||||
#' @param title Display title for tab
|
||||
#' @param ... UI elements to include within the tab
|
||||
|
||||
30
R/globals.R
30
R/globals.R
@@ -1,11 +1,41 @@
|
||||
# A scope where we can put mutable global state
|
||||
.globals <- new.env(parent = emptyenv())
|
||||
|
||||
register_s3_method <- function(pkg, generic, class, fun = NULL) {
|
||||
stopifnot(is.character(pkg), length(pkg) == 1)
|
||||
stopifnot(is.character(generic), length(generic) == 1)
|
||||
stopifnot(is.character(class), length(class) == 1)
|
||||
|
||||
if (is.null(fun)) {
|
||||
fun <- get(paste0(generic, ".", class), envir = parent.frame())
|
||||
} else {
|
||||
stopifnot(is.function(fun))
|
||||
}
|
||||
|
||||
if (pkg %in% loadedNamespaces()) {
|
||||
registerS3method(generic, class, fun, envir = asNamespace(pkg))
|
||||
}
|
||||
|
||||
# Always register hook in case package is later unloaded & reloaded
|
||||
setHook(
|
||||
packageEvent(pkg, "onLoad"),
|
||||
function(...) {
|
||||
registerS3method(generic, class, fun, envir = asNamespace(pkg))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
.onLoad <- function(libname, pkgname) {
|
||||
# R's lazy-loading package scheme causes the private seed to be cached in the
|
||||
# package itself, making our PRNG completely deterministic. This line resets
|
||||
# the private seed during load.
|
||||
withPrivateSeed(set.seed(NULL))
|
||||
|
||||
# Make sure these methods are available to knitr if shiny is loaded but not
|
||||
# attached.
|
||||
register_s3_method("knitr", "knit_print", "reactive")
|
||||
register_s3_method("knitr", "knit_print", "shiny.appobj")
|
||||
register_s3_method("knitr", "knit_print", "shiny.render.function")
|
||||
}
|
||||
|
||||
.onAttach <- function(libname, pkgname) {
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#' @export a br code div em h1 h2 h3 h4 h5 h6 hr HTML img p pre span strong
|
||||
#' @export includeCSS includeHTML includeMarkdown includeScript includeText
|
||||
#' @export is.singleton singleton
|
||||
#' @export tag tagAppendAttributes tagAppendChild tagAppendChildren tagList tags tagSetChildren withTags
|
||||
#' @import htmltools
|
||||
#' @export tags p h1 h2 h3 h4 h5 h6 a br div span pre code img strong em hr
|
||||
#' @export tag tagList tagAppendAttributes tagHasAttribute tagGetAttribute tagAppendChild tagAppendChildren tagSetChildren
|
||||
#' @export HTML
|
||||
#' @export includeHTML includeText includeMarkdown includeCSS includeScript
|
||||
#' @export singleton is.singleton
|
||||
#' @export validateCssUnit
|
||||
#' @export knit_print.html knit_print.shiny.tag knit_print.shiny.tag.list
|
||||
#' @export htmlTemplate suppressDependencies
|
||||
#' @export htmlTemplate
|
||||
#' @export suppressDependencies
|
||||
#' @export withTags
|
||||
NULL
|
||||
|
||||
@@ -90,18 +90,18 @@ generateOptions <- function(inputId, selected, inline, type = 'checkbox',
|
||||
div(class = "shiny-options-group", options)
|
||||
}
|
||||
|
||||
# True when a choice list item represents a group of related inputs
|
||||
# True when a choice list item represents a group of related inputs.
|
||||
isGroup <- function(choice) {
|
||||
length(choice) > 1 || !is.null(names(choice))
|
||||
}
|
||||
|
||||
# True when choices is a list and contains at least one group of related inputs
|
||||
# True when choices is a list and contains at least one group of related inputs.
|
||||
hasGroups <- function(choices) {
|
||||
is.list(choices) && Position(isGroup, choices, nomatch = 0)
|
||||
is.list(choices) && any(vapply(choices, isGroup, logical(1)))
|
||||
}
|
||||
|
||||
# Assigns empty names to x if it's unnamed, and then fills any empty names with
|
||||
# the corresponding value coerced to a character(1)
|
||||
# the corresponding value coerced to a character(1).
|
||||
setDefaultNames <- function(x) {
|
||||
x <- asNamed(x)
|
||||
emptyNames <- names(x) == ""
|
||||
@@ -109,37 +109,55 @@ setDefaultNames <- function(x) {
|
||||
x
|
||||
}
|
||||
|
||||
# Makes a character vector out of x in a way that preserves names if x is a
|
||||
# factor.
|
||||
# Makes a character vector out of x in a way that preserves names.
|
||||
asCharacter <- function(x) {
|
||||
stats::setNames(as.character(x), names(x))
|
||||
}
|
||||
|
||||
# Processes a "flat" set of choices, or a collection of choices not containing
|
||||
# any named groups. choices should be a list without any list children, or an
|
||||
# atomic vector. choices may be named or unnamed. Any empty names are replaced
|
||||
# with the corresponding value coerced to a character.
|
||||
processFlatChoices <- function(choices) {
|
||||
choices <- setDefaultNames(asCharacter(choices))
|
||||
as.list(choices)
|
||||
}
|
||||
|
||||
# Processes a "nested" set of choices, or a collection of choices that contains
|
||||
# one or more named groups of related choices and zero or more "flat" choices.
|
||||
# choices should be a named list, and any choice group must have a non-empty
|
||||
# name. Empty names of remaining "flat" choices are replaced with that choice's
|
||||
# value coerced to a character.
|
||||
processGroupedChoices <- function(choices) {
|
||||
choices <- asNamed(choices)
|
||||
choices <- mapply(function(name, group, choice) {
|
||||
if (group && name == "") {
|
||||
# We assert choices is a list, since only a list may contain a group.
|
||||
stopifnot(is.list(choices))
|
||||
choices <- mapply(function(name, choice) {
|
||||
choiceIsGroup <- isGroup(choice)
|
||||
if (choiceIsGroup && name == "") {
|
||||
# If the choice is a group, and if its name is empty, produce an error. We
|
||||
# error here because the composite nature of the choice prevents us from
|
||||
# meaningfully automatically naming it. Note that while not documented,
|
||||
# groups are not necessarily lists (aka generic vectors) but can also be
|
||||
# any named atomic vector, or any atomic vector of length > 1.
|
||||
stop('All sub-lists in "choices" must be named.')
|
||||
} else if (group) {
|
||||
} else if (choiceIsGroup) {
|
||||
# The choice is a group, but it is named. Process it using the same
|
||||
# function we use for "top level" choices.
|
||||
processFlatChoices(choice)
|
||||
} else {
|
||||
# The choice was not named and is not a group; it is a "leaf".
|
||||
as.character(choice)
|
||||
}
|
||||
}, names(choices), lapply(choices, isGroup), choices, SIMPLIFY = FALSE)
|
||||
}, names(choices), choices, SIMPLIFY = FALSE)
|
||||
# By this point, any leaves in the choices list might still have empty names,
|
||||
# so we're sure to automatically name them.
|
||||
setDefaultNames(choices)
|
||||
}
|
||||
|
||||
# Takes a vector or list, and adds names (same as the value) to any entries
|
||||
# Takes a vector/list/factor, and adds names (same as the value) to any entries
|
||||
# without names. Coerces all leaf nodes to `character`.
|
||||
choicesWithNames <- function(choices) {
|
||||
if (length(choices) == 0) {
|
||||
choices
|
||||
} else if (hasGroups(choices)) {
|
||||
if (hasGroups(choices)) {
|
||||
processGroupedChoices(choices)
|
||||
} else {
|
||||
processFlatChoices(choices)
|
||||
|
||||
@@ -199,6 +199,9 @@ staticHandler <- function(root) {
|
||||
if (path == '/')
|
||||
path <- '/index.html'
|
||||
|
||||
if (grepl('\\', path, fixed = TRUE))
|
||||
return(NULL)
|
||||
|
||||
abs.path <- resolve(root, path)
|
||||
if (is.null(abs.path))
|
||||
return(NULL)
|
||||
|
||||
@@ -590,6 +590,14 @@ checkName <- function(x) {
|
||||
)
|
||||
}
|
||||
|
||||
#' @export
|
||||
print.reactivevalues <- function(x, ...) {
|
||||
impl <- .subset2(x, "impl")
|
||||
cat_line("<ReactiveValues>")
|
||||
cat_line(" Values: ", paste0(impl$.values$keys(sort = TRUE), collapse = ", "))
|
||||
cat_line(" Readonly: ", .subset2(x, "readonly"))
|
||||
}
|
||||
|
||||
#' Checks whether an object is a reactivevalues object
|
||||
#'
|
||||
#' Checks whether its argument is a reactivevalues object.
|
||||
@@ -660,14 +668,14 @@ as.list.reactivevalues <- function(x, all.names=FALSE, ...) {
|
||||
|
||||
#' Convert a reactivevalues object to a list
|
||||
#'
|
||||
#' This function does something similar to what you might [base::as.list()]
|
||||
#' to do. The difference is that the calling context will take dependencies on
|
||||
#' every object in the reactivevalues object. To avoid taking dependencies on
|
||||
#' all the objects, you can wrap the call with [isolate()].
|
||||
#' This function does something similar to what you might want or expect
|
||||
#' [base::as.list()] to do. The difference is that the calling context will take
|
||||
#' dependencies on every object in the `reactivevalue`s object. To avoid taking
|
||||
#' dependencies on all the objects, you can wrap the call with [isolate()].
|
||||
#'
|
||||
#' @param x A reactivevalues object.
|
||||
#' @param all.names If `TRUE`, include objects with a leading dot. If
|
||||
#' `FALSE` (the default) don't include those objects.
|
||||
#' @param x A `reactivevalues` object.
|
||||
#' @param all.names If `TRUE`, include objects with a leading dot. If `FALSE`
|
||||
#' (the default) don't include those objects.
|
||||
#' @examples
|
||||
#' values <- reactiveValues(a = 1)
|
||||
#' \dontrun{
|
||||
@@ -912,7 +920,7 @@ Observable <- R6Class(
|
||||
#' marked as invalidated. In this way, invalidations ripple through the
|
||||
#' expressions that depend on each other.
|
||||
#'
|
||||
#' See the [Shiny tutorial](http://rstudio.github.com/shiny/tutorial/) for
|
||||
#' See the [Shiny tutorial](https://shiny.rstudio.com/tutorial/) for
|
||||
#' more information about reactive expressions.
|
||||
#'
|
||||
#' @param x For `reactive`, an expression (quoted or unquoted). For
|
||||
@@ -1611,12 +1619,16 @@ invalidateLater <- function(millis, session = getDefaultReactiveDomain()) {
|
||||
ctx <- getCurrentContext()
|
||||
rLog$invalidateLater(ctx$.reactId, ctx$id, millis, session)
|
||||
|
||||
clear_on_ended_callback <- function() {}
|
||||
|
||||
timerHandle <- scheduleTask(millis, function() {
|
||||
if (is.null(session)) {
|
||||
ctx$invalidate()
|
||||
return(invisible())
|
||||
}
|
||||
|
||||
clear_on_ended_callback()
|
||||
|
||||
if (!session$isClosed()) {
|
||||
session$cycleStartAction(function() {
|
||||
ctx$invalidate()
|
||||
@@ -1627,7 +1639,13 @@ invalidateLater <- function(millis, session = getDefaultReactiveDomain()) {
|
||||
})
|
||||
|
||||
if (!is.null(session)) {
|
||||
session$onEnded(timerHandle)
|
||||
# timerHandle is a callback that clears the scheduled task. It gets
|
||||
# registered with session$onEnded() each time invalidateLater() is called.
|
||||
# So, to prevent these callbacks from building up and leaking memory, we
|
||||
# need to deregister the onEnded(timerHandle) callback each time when the
|
||||
# scheduled task executes; after the task executes, the timerHandle()
|
||||
# function is essentially a no-op, so we can deregister it.
|
||||
clear_on_ended_callback <- session$onEnded(timerHandle)
|
||||
}
|
||||
|
||||
invisible()
|
||||
@@ -1715,7 +1733,18 @@ reactivePoll <- function(intervalMillis, session, checkFunc, valueFunc) {
|
||||
|
||||
rv <- reactiveValues(cookie = isolate(checkFunc()))
|
||||
|
||||
observe({
|
||||
re_finalized <- FALSE
|
||||
|
||||
o <- observe({
|
||||
# When no one holds a reference to the reactive returned from
|
||||
# reactivePoll, destroy and remove the observer so that it doesn't keep
|
||||
# firing and hold onto resources.
|
||||
if (re_finalized) {
|
||||
o$destroy()
|
||||
rm(o, envir = parent.env(environment()))
|
||||
return()
|
||||
}
|
||||
|
||||
rv$cookie <- checkFunc()
|
||||
invalidateLater(intervalMillis(), session)
|
||||
})
|
||||
@@ -1728,6 +1757,14 @@ reactivePoll <- function(intervalMillis, session, checkFunc, valueFunc) {
|
||||
|
||||
}, label = NULL)
|
||||
|
||||
reg.finalizer(attr(re, "observable"), function(e) {
|
||||
re_finalized <<- TRUE
|
||||
})
|
||||
|
||||
# So that the observer and finalizer function don't (indirectly) hold onto a
|
||||
# reference to `re` and thus prevent it from getting GC'd.
|
||||
on.exit(rm(re))
|
||||
|
||||
return(re)
|
||||
}
|
||||
|
||||
|
||||
@@ -22,13 +22,17 @@
|
||||
#' expedite the rendering of identical plots.
|
||||
#'
|
||||
#' @param expr An expression that generates a plot.
|
||||
#' @param width,height The width/height of the rendered plot, in pixels; or
|
||||
#' `'auto'` to use the `offsetWidth`/`offsetHeight` of the HTML
|
||||
#' element that is bound to this plot. You can also pass in a function that
|
||||
#' returns the width/height in pixels or `'auto'`; in the body of the
|
||||
#' function you may reference reactive values and functions. When rendering an
|
||||
#' inline plot, you must provide numeric values (in pixels) to both
|
||||
#' `width` and `height`.
|
||||
#' @param width,height Height and width can be specified in three ways:
|
||||
#' * `"auto"`, the default, uses the size specified by [plotOutput()]
|
||||
#' (i.e. the `offsetWidth`/`offsetHeight`` of the HTML element bound to
|
||||
#' this plot.)
|
||||
#' * An integer, defining the width/height in pixels.
|
||||
#' * A function that returns the width/height in pixels (or `"auto"`).
|
||||
#' The function is executed in a reactive context so that you can refer to
|
||||
#' reactive values and expression to make the width/height reactive.
|
||||
#'
|
||||
#' When rendering an inline plot, you must provide numeric values (in pixels)
|
||||
#' to both \code{width} and \code{height}.
|
||||
#' @param res Resolution of resulting plot, in pixels per inch. This value is
|
||||
#' passed to [grDevices::png()]. Note that this affects the resolution of PNG
|
||||
#' rendering in R; it won't change the actual ppi of the browser.
|
||||
|
||||
127
R/server.R
127
R/server.R
@@ -31,24 +31,46 @@ registerClient <- function(client) {
|
||||
|
||||
#' Resource Publishing
|
||||
#'
|
||||
#' Adds a directory of static resources to Shiny's web server, with the given
|
||||
#' path prefix. Primarily intended for package authors to make supporting
|
||||
#' JavaScript/CSS files available to their components.
|
||||
#' Add, remove, or list directory of static resources to Shiny's web server,
|
||||
#' with the given path prefix. Primarily intended for package authors to make
|
||||
#' supporting JavaScript/CSS files available to their components.
|
||||
#'
|
||||
#' Shiny provides two ways of serving static files (i.e., resources):
|
||||
#'
|
||||
#' 1. Static files under the `www/` directory are automatically made available
|
||||
#' under a request path that begins with `/`.
|
||||
#' 2. `addResourcePath()` makes static files in a `directoryPath` available
|
||||
#' under a request path that begins with `prefix`.
|
||||
#'
|
||||
#' The second approach is primarily intended for package authors to make
|
||||
#' supporting JavaScript/CSS files available to their components.
|
||||
#'
|
||||
#' Tools for managing static resources published by Shiny's web server:
|
||||
#' * `addResourcePath()` adds a directory of static resources.
|
||||
#' * `resourcePaths()` lists the currently active resource mappings.
|
||||
#' * `removeResourcePath()` removes a directory of static resources.
|
||||
#'
|
||||
#' @param prefix The URL prefix (without slashes). Valid characters are a-z,
|
||||
#' A-Z, 0-9, hyphen, period, and underscore.
|
||||
#' For example, a value of 'foo' means that any request paths that begin with
|
||||
#' '/foo' will be mapped to the given directory.
|
||||
#' A-Z, 0-9, hyphen, period, and underscore. For example, a value of 'foo'
|
||||
#' means that any request paths that begin with '/foo' will be mapped to the
|
||||
#' given directory.
|
||||
#' @param directoryPath The directory that contains the static resources to be
|
||||
#' served.
|
||||
#'
|
||||
#' @rdname resourcePaths
|
||||
#' @seealso [singleton()]
|
||||
#'
|
||||
#' @examples
|
||||
#' addResourcePath('datasets', system.file('data', package='datasets'))
|
||||
#' resourcePaths()
|
||||
#' removeResourcePath('datasets')
|
||||
#' resourcePaths()
|
||||
#'
|
||||
#' # make sure all resources are removed
|
||||
#' lapply(names(resourcePaths()), removeResourcePath)
|
||||
#' @export
|
||||
addResourcePath <- function(prefix, directoryPath) {
|
||||
prefix <- prefix[1]
|
||||
if (length(prefix) != 1) stop("prefix must be of length 1")
|
||||
if (!grepl('^[a-z0-9\\-_][a-z0-9\\-_.]*$', prefix, ignore.case = TRUE, perl = TRUE)) {
|
||||
stop("addResourcePath called with invalid prefix; please see documentation")
|
||||
}
|
||||
@@ -63,6 +85,26 @@ addResourcePath <- function(prefix, directoryPath) {
|
||||
}
|
||||
)
|
||||
|
||||
# # Often times overwriting a resource path is "what you want",
|
||||
# # but sometimes it can lead to difficult to diagnose issues
|
||||
# # (e.g. an implict dependency might set a resource path that
|
||||
# # conflicts with what you, the app author, are trying to register)
|
||||
# # Note that previous versions of shiny used to warn about this case,
|
||||
# # but it was eventually removed since it caused confusion (#567).
|
||||
# # It seems a good compromise is to throw a more information message.
|
||||
# if (getOption("shiny.resourcePathChanges", FALSE) &&
|
||||
# prefix %in% names(.globals$resourcePaths)) {
|
||||
# existingPath <- .globals$resourcePaths[[prefix]]$path
|
||||
# if (normalizedPath != existingPath) {
|
||||
# message(
|
||||
# "The resource path '", prefix, "' used to point to ",
|
||||
# existingPath, ", but it now points to ", normalizedPath, ". ",
|
||||
# "If your app doesn't work as expected, you may want to ",
|
||||
# "choose a different prefix name."
|
||||
# )
|
||||
# }
|
||||
# }
|
||||
|
||||
# If a shiny app is currently running, dynamically register this path with
|
||||
# the corresponding httpuv server object.
|
||||
if (!is.null(getShinyOption("server")))
|
||||
@@ -82,6 +124,33 @@ addResourcePath <- function(prefix, directoryPath) {
|
||||
)
|
||||
}
|
||||
|
||||
#' @rdname resourcePaths
|
||||
#' @export
|
||||
resourcePaths <- function() {
|
||||
urls <- names(.globals$resourcePaths)
|
||||
paths <- vapply(.globals$resourcePaths, function(x) x$path, character(1))
|
||||
stats::setNames(paths, urls)
|
||||
}
|
||||
|
||||
hasResourcePath <- function(prefix) {
|
||||
prefix %in% names(resourcePaths())
|
||||
}
|
||||
|
||||
#' @rdname resourcePaths
|
||||
#' @export
|
||||
removeResourcePath <- function(prefix) {
|
||||
if (length(prefix) > 1) stop("`prefix` must be of length 1.")
|
||||
if (!hasResourcePath(prefix)) {
|
||||
warning("Resource ", prefix, " not found.")
|
||||
return(invisible(FALSE))
|
||||
}
|
||||
.globals$resourcePaths[[prefix]] <- NULL
|
||||
.globals$resources[[prefix]] <- NULL
|
||||
invisible(TRUE)
|
||||
}
|
||||
|
||||
|
||||
|
||||
# This function handles any GET request with two or more path elements where the
|
||||
# first path element matches a prefix that was previously added using
|
||||
# addResourcePath().
|
||||
@@ -459,6 +528,49 @@ startApp <- function(appObj, port, host, quiet) {
|
||||
),
|
||||
.globals$resourcePaths
|
||||
)
|
||||
|
||||
# throw an informative warning if a subdirectory of the
|
||||
# app's www dir conflicts with another resource prefix
|
||||
wwwDir <- httpuvApp$staticPaths[["/"]]$path
|
||||
if (length(wwwDir)) {
|
||||
# although httpuv allows for resource prefixes like 'foo/bar',
|
||||
# we won't worry about conflicts in sub-sub directories since
|
||||
# addResourcePath() currently doesn't allow it
|
||||
wwwSubDirs <- list.dirs(wwwDir, recursive = FALSE, full.names = FALSE)
|
||||
resourceConflicts <- intersect(wwwSubDirs, names(httpuvApp$staticPaths))
|
||||
if (length(resourceConflicts)) {
|
||||
warning(
|
||||
"Found subdirectories of your app's www/ directory that ",
|
||||
"conflict with other resource URL prefixes. ",
|
||||
"Consider renaming these directories: '",
|
||||
paste0("www/", resourceConflicts, collapse = "', '"), "'",
|
||||
call. = FALSE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
# check for conflicts in each pairwise combinations of resource mappings
|
||||
checkResourceConflict <- function(paths) {
|
||||
if (length(paths) < 2) return(NULL)
|
||||
# ensure paths is a named character vector: c(resource_path = local_path)
|
||||
paths <- vapply(paths, function(x) if (inherits(x, "staticPath")) x$path else x, character(1))
|
||||
# get all possible pairwise combinations of paths
|
||||
pair_indices <- utils::combn(length(paths), 2, simplify = FALSE)
|
||||
lapply(pair_indices, function(x) {
|
||||
p1 <- paths[x[1]]
|
||||
p2 <- paths[x[2]]
|
||||
if (identical(names(p1), names(p2)) && (p1 != p2)) {
|
||||
warning(
|
||||
"Found multiple local file paths pointing the same resource prefix: ", names(p1), ". ",
|
||||
"If you run into resource-related issues (e.g. 404 requests), consider ",
|
||||
"using `addResourcePath()` and/or `removeResourcePath()` to manage resource mappings.",
|
||||
call. = FALSE
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
checkResourceConflict(httpuvApp$staticPaths)
|
||||
|
||||
httpuvApp$staticPathOptions <- httpuv::staticPathOptions(
|
||||
html_charset = "utf-8",
|
||||
headers = list("X-UA-Compatible" = "IE=edge,chrome=1"),
|
||||
@@ -875,7 +987,6 @@ runApp <- function(appDir=getwd(),
|
||||
captureStackTraces({
|
||||
while (!.globals$stopped) {
|
||||
..stacktracefloor..(serviceApp())
|
||||
Sys.sleep(0.001)
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
@@ -16,20 +16,102 @@ getShinyOption <- function(name, default = NULL) {
|
||||
|
||||
#' Get or set Shiny options
|
||||
#'
|
||||
#' `getShinyOption` retrieves the value of a Shiny option.
|
||||
#' `shinyOptions` sets the value of Shiny options; it can also be used to
|
||||
#' return a list of all currently-set Shiny options.
|
||||
#' `getShinyOption()` retrieves the value of a Shiny option. `shinyOptions()`
|
||||
#' sets the value of Shiny options; it can also be used to return a list of all
|
||||
#' currently-set Shiny options.
|
||||
#'
|
||||
#' There is a global option set, which is available by default. When a Shiny
|
||||
#' application is run with [runApp()], that option set is duplicated
|
||||
#' and the new option set is available for getting or setting values. If options
|
||||
#' are set from global.R, app.R, ui.R, or server.R, or if they are set from
|
||||
#' inside the server function, then the options will be scoped to the
|
||||
#' @section Scope:
|
||||
#' There is a global option set which is available by default. When a Shiny
|
||||
#' application is run with [runApp()], that option set is duplicated and the
|
||||
#' new option set is available for getting or setting values. If options
|
||||
#' are set from `global.R`, `app.R`, `ui.R`, or `server.R`, or if they are set
|
||||
#' from inside the server function, then the options will be scoped to the
|
||||
#' application. When the application exits, the new option set is discarded and
|
||||
#' the global option set is restored.
|
||||
#'
|
||||
#' @param ... Options to set, with the form `name = value`.
|
||||
#' @section Options:
|
||||
#' There are a number of global options that affect Shiny's behavior. These can
|
||||
#' be set globally with `options()` or locally (for a single app) with
|
||||
#' `shinyOptions()`.
|
||||
#'
|
||||
#' \describe{
|
||||
#' \item{shiny.autoreload}{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.
|
||||
#'
|
||||
#' 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}{This controls whether messages for
|
||||
#' deprecated functions in Shiny will be printed. See
|
||||
#' [shinyDeprecated()] for more information.}
|
||||
#' \item{shiny.error}{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}{Controls whether "pretty" or full stack traces
|
||||
#' are dumped to the console when errors occur during Shiny app execution.
|
||||
#' The default is `FALSE` (pretty stack traces).}
|
||||
#' \item{shiny.host}{The IP address that Shiny should listen on. See
|
||||
#' [runApp()] for more information.}
|
||||
#' \item{shiny.json.digits}{The number of digits to use when converting
|
||||
#' numbers to JSON format to send to the client web browser.}
|
||||
#' \item{shiny.launch.browser}{A boolean which controls the default behavior
|
||||
#' when an app is run. See [runApp()] for more information.}
|
||||
#' \item{shiny.maxRequestSize}{This is a number which specifies the maximum
|
||||
#' web request size, which serves as a size limit for file uploads. If
|
||||
#' unset, the maximum request size defaults to 5MB.}
|
||||
#' \item{shiny.minified}{If this is `TRUE` or unset (the default), then
|
||||
#' Shiny will use minified JavaScript (`shiny.min.js`). If
|
||||
#' `FALSE`, then Shiny will use the un-minified JavaScript
|
||||
#' (`shiny.js`); this can be useful during development.}
|
||||
#' \item{shiny.port}{A port number that Shiny will listen on. See
|
||||
#' [runApp()] for more information.}
|
||||
#' \item{shiny.reactlog}{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}{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). The default is `FALSE` (unsanitized
|
||||
#' errors).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}{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}{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.table.class}{CSS class names to use for tables.}
|
||||
#' \item{shiny.testmode}{If `TRUE`, then enable features for testing Shiny
|
||||
#' applications. If `FALSE` (the default), do not enable those features.}
|
||||
#' \item{shiny.trace}{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}{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
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' shinyOptions(myOption = 10)
|
||||
|
||||
95
R/shiny.R
95
R/shiny.R
@@ -28,91 +28,6 @@ NULL
|
||||
#' @import methods
|
||||
NULL
|
||||
|
||||
|
||||
#' Global options for Shiny
|
||||
#'
|
||||
#' There are a number of global options that affect Shiny's behavior. These can
|
||||
#' be set with (for example) `options(shiny.trace=TRUE)`.
|
||||
#'
|
||||
#' \describe{
|
||||
#' \item{shiny.launch.browser}{A boolean which controls the default behavior
|
||||
#' when an app is run. See [runApp()] for more information.}
|
||||
#' \item{shiny.port}{A port number that Shiny will listen on. See
|
||||
#' [runApp()] for more information.}
|
||||
#' \item{shiny.trace}{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.autoreload}{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.
|
||||
#'
|
||||
#' 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.reactlog}{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.usecairo}{This is used to disable graphical rendering by the
|
||||
#' Cairo package, if it is installed. See [plotPNG()] for more
|
||||
#' information.}
|
||||
#' \item{shiny.maxRequestSize}{This is a number which specifies the maximum
|
||||
#' web request size, which serves as a size limit for file uploads. If
|
||||
#' unset, the maximum request size defaults to 5MB.}
|
||||
#' \item{shiny.suppressMissingContextError}{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.host}{The IP address that Shiny should listen on. See
|
||||
#' [runApp()] for more information.}
|
||||
#' \item{shiny.json.digits}{The number of digits to use when converting
|
||||
#' numbers to JSON format to send to the client web browser.}
|
||||
#' \item{shiny.minified}{If this is `TRUE` or unset (the default), then
|
||||
#' Shiny will use minified JavaScript (`shiny.min.js`). If
|
||||
#' `FALSE`, then Shiny will use the un-minified JavaScript
|
||||
#' (`shiny.js`); this can be useful during development.}
|
||||
#' \item{shiny.error}{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.table.class}{CSS class names to use for tables.}
|
||||
#' \item{shiny.deprecation.messages}{This controls whether messages for
|
||||
#' deprecated functions in Shiny will be printed. See
|
||||
#' [shinyDeprecated()] for more information.}
|
||||
#' \item{shiny.fullstacktrace}{Controls whether "pretty" or full stack traces
|
||||
#' are dumped to the console when errors occur during Shiny app execution.
|
||||
#' The default is `FALSE` (pretty stack traces).}
|
||||
#' \item{shiny.stacktraceoffset}{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.sanitize.errors}{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). The default is `FALSE` (unsanitized
|
||||
#' errors).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.testmode}{If `TRUE`, then enable features for testing Shiny
|
||||
#' applications. If `FALSE` (the default), do not enable those features.
|
||||
#' }
|
||||
#' }
|
||||
#' @name shiny-options
|
||||
NULL
|
||||
createUniqueId <- function(bytes, prefix = "", suffix = "") {
|
||||
withPrivateSeed({
|
||||
paste(
|
||||
@@ -1629,8 +1544,14 @@ ShinySession <- R6Class(
|
||||
reactlog = function(logEntry) {
|
||||
# Use sendCustomMessage instead of sendMessage, because the handler in
|
||||
# shiny-showcase.js only has access to public API of the Shiny object.
|
||||
if (private$showcase)
|
||||
self$sendCustomMessage("reactlog", logEntry)
|
||||
if (private$showcase) {
|
||||
srcref <- logEntry$srcref
|
||||
srcfile <- logEntry$srcfile
|
||||
if (!is.null(srcref) && !is.null(srcfile)) {
|
||||
# only send needed information, not all of reactlog info.
|
||||
self$sendCustomMessage("showcase-src", list(srcref = srcref, srcfile = srcfile))
|
||||
}
|
||||
}
|
||||
},
|
||||
reload = function() {
|
||||
private$sendMessage(reload = TRUE)
|
||||
|
||||
@@ -44,7 +44,7 @@ renderPage <- function(ui, connection, showcase=0, testMode=FALSE) {
|
||||
|
||||
shiny_deps <- list(
|
||||
htmlDependency("json2", "2014.02.04", c(href="shared"), script = "json2-min.js"),
|
||||
htmlDependency("jquery", "1.12.4", c(href="shared"), script = "jquery.min.js"),
|
||||
htmlDependency("jquery", "3.4.1", c(href="shared"), script = "jquery.min.js"),
|
||||
htmlDependency("shiny", utils::packageVersion("shiny"), c(href="shared"),
|
||||
script = if (getOption("shiny.minified", TRUE)) "shiny.min.js" else "shiny.js",
|
||||
stylesheet = "shiny.css")
|
||||
|
||||
@@ -52,6 +52,11 @@ markRenderFunction <- function(uiFunc, renderFunc, outputArgs = list()) {
|
||||
hasExecuted = hasExecuted)
|
||||
}
|
||||
|
||||
#' @export
|
||||
print.shiny.render.function <- function(x, ...) {
|
||||
cat_line("<shiny.render.function>")
|
||||
}
|
||||
|
||||
#' Implement render functions
|
||||
#'
|
||||
#' @param func A function without parameters, that returns user data. If the
|
||||
|
||||
@@ -1800,3 +1800,8 @@ constantTimeEquals <- function(raw1, raw2) {
|
||||
|
||||
sum(as.integer(xor(raw1, raw2))) == 0
|
||||
}
|
||||
|
||||
cat_line <- function(...) {
|
||||
cat(paste(..., "\n", collapse = ""))
|
||||
}
|
||||
|
||||
|
||||
@@ -9,15 +9,11 @@ sd_section("UI Layout",
|
||||
"fillRow",
|
||||
"fixedPage",
|
||||
"fluidPage",
|
||||
"headerPanel",
|
||||
"helpText",
|
||||
"icon",
|
||||
"mainPanel",
|
||||
"navbarPage",
|
||||
"navlistPanel",
|
||||
"pageWithSidebar",
|
||||
"sidebarLayout",
|
||||
"sidebarPanel",
|
||||
"tabPanel",
|
||||
"tabsetPanel",
|
||||
"titlePanel",
|
||||
@@ -155,7 +151,8 @@ sd_section("Running",
|
||||
"runUrl",
|
||||
"stopApp",
|
||||
"viewer",
|
||||
"isRunning"
|
||||
"isRunning",
|
||||
"loadSupport"
|
||||
)
|
||||
)
|
||||
sd_section("Bookmarking state",
|
||||
@@ -172,7 +169,7 @@ sd_section("Extending Shiny",
|
||||
"Functions that are intended to be called by third-party packages that extend Shiny.",
|
||||
c(
|
||||
"createWebDependency",
|
||||
"addResourcePath",
|
||||
"resourcePaths",
|
||||
"registerInputHandler",
|
||||
"removeInputHandler",
|
||||
"markRenderFunction"
|
||||
@@ -204,7 +201,6 @@ sd_section("Utility functions",
|
||||
"repeatable",
|
||||
"shinyDeprecated",
|
||||
"serverInfo",
|
||||
"shiny-options",
|
||||
"onStop",
|
||||
"diskCache",
|
||||
"memoryCache",
|
||||
|
||||
200
inst/www/shared/bootstrap/css/bootstrap-theme.css
vendored
200
inst/www/shared/bootstrap/css/bootstrap-theme.css
vendored
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* Bootstrap v3.3.7 (http://getbootstrap.com)
|
||||
* Copyright 2011-2016 Twitter, Inc.
|
||||
* Bootstrap v3.4.1 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2019 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
*/
|
||||
.btn-default,
|
||||
@@ -9,9 +9,9 @@
|
||||
.btn-info,
|
||||
.btn-warning,
|
||||
.btn-danger {
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
|
||||
}
|
||||
.btn-default:active,
|
||||
.btn-primary:active,
|
||||
@@ -25,8 +25,8 @@
|
||||
.btn-info.active,
|
||||
.btn-warning.active,
|
||||
.btn-danger.active {
|
||||
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
|
||||
box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
|
||||
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
|
||||
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
|
||||
}
|
||||
.btn-default.disabled,
|
||||
.btn-primary.disabled,
|
||||
@@ -47,7 +47,7 @@ fieldset[disabled] .btn-info,
|
||||
fieldset[disabled] .btn-warning,
|
||||
fieldset[disabled] .btn-danger {
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.btn-default .badge,
|
||||
.btn-primary .badge,
|
||||
@@ -62,15 +62,15 @@ fieldset[disabled] .btn-danger {
|
||||
background-image: none;
|
||||
}
|
||||
.btn-default {
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
|
||||
background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
|
||||
background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
|
||||
background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
|
||||
background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dbdbdb;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
border-color: #ccc;
|
||||
}
|
||||
.btn-default:hover,
|
||||
@@ -106,9 +106,9 @@ fieldset[disabled] .btn-default.active {
|
||||
}
|
||||
.btn-primary {
|
||||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88));
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
@@ -147,9 +147,9 @@ fieldset[disabled] .btn-primary.active {
|
||||
}
|
||||
.btn-success {
|
||||
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
|
||||
background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);
|
||||
background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));
|
||||
background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
|
||||
background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
@@ -188,9 +188,9 @@ fieldset[disabled] .btn-success.active {
|
||||
}
|
||||
.btn-info {
|
||||
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
|
||||
background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
|
||||
background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));
|
||||
background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
|
||||
background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
@@ -229,9 +229,9 @@ fieldset[disabled] .btn-info.active {
|
||||
}
|
||||
.btn-warning {
|
||||
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
|
||||
background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
|
||||
background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));
|
||||
background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
|
||||
background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
@@ -270,9 +270,9 @@ fieldset[disabled] .btn-warning.active {
|
||||
}
|
||||
.btn-danger {
|
||||
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
|
||||
background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
|
||||
background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));
|
||||
background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
|
||||
background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
@@ -311,81 +311,81 @@ fieldset[disabled] .btn-danger.active {
|
||||
}
|
||||
.thumbnail,
|
||||
.img-thumbnail {
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
}
|
||||
.dropdown-menu > li > a:hover,
|
||||
.dropdown-menu > li > a:focus {
|
||||
background-color: #e8e8e8;
|
||||
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
|
||||
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
background-color: #e8e8e8;
|
||||
}
|
||||
.dropdown-menu > .active > a,
|
||||
.dropdown-menu > .active > a:hover,
|
||||
.dropdown-menu > .active > a:focus {
|
||||
background-color: #2e6da4;
|
||||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
background-color: #2e6da4;
|
||||
}
|
||||
.navbar-default {
|
||||
background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
|
||||
background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));
|
||||
background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
|
||||
background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);
|
||||
background-image: -o-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#f8f8f8));
|
||||
background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);
|
||||
}
|
||||
.navbar-default .navbar-nav > .open > a,
|
||||
.navbar-default .navbar-nav > .active > a {
|
||||
background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
|
||||
background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
|
||||
background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));
|
||||
background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);
|
||||
background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
|
||||
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
|
||||
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);
|
||||
box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);
|
||||
}
|
||||
.navbar-brand,
|
||||
.navbar-nav > li > a {
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
.navbar-inverse {
|
||||
background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
|
||||
background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%);
|
||||
background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));
|
||||
background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
|
||||
background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.navbar-inverse .navbar-nav > .open > a,
|
||||
.navbar-inverse .navbar-nav > .active > a {
|
||||
background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);
|
||||
background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);
|
||||
background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f));
|
||||
background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);
|
||||
background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
|
||||
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
|
||||
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);
|
||||
box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
.navbar-inverse .navbar-brand,
|
||||
.navbar-inverse .navbar-nav > li > a {
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
.navbar-static-top,
|
||||
.navbar-fixed-top,
|
||||
@@ -398,120 +398,120 @@ fieldset[disabled] .btn-danger.active {
|
||||
.navbar .navbar-nav .open .dropdown-menu > .active > a:focus {
|
||||
color: #fff;
|
||||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
}
|
||||
.alert {
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.alert-success {
|
||||
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
|
||||
background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
|
||||
background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));
|
||||
background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
|
||||
background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #b2dba1;
|
||||
}
|
||||
.alert-info {
|
||||
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
|
||||
background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
|
||||
background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));
|
||||
background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
|
||||
background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #9acfea;
|
||||
}
|
||||
.alert-warning {
|
||||
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
|
||||
background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
|
||||
background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));
|
||||
background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
|
||||
background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #f5e79e;
|
||||
}
|
||||
.alert-danger {
|
||||
background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
|
||||
background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
|
||||
background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));
|
||||
background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
|
||||
background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dca7a7;
|
||||
}
|
||||
.progress {
|
||||
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
|
||||
background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
|
||||
background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));
|
||||
background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
|
||||
background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar {
|
||||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090));
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-success {
|
||||
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
|
||||
background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);
|
||||
background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));
|
||||
background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
|
||||
background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-info {
|
||||
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
|
||||
background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
|
||||
background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));
|
||||
background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
|
||||
background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-warning {
|
||||
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
|
||||
background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
|
||||
background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));
|
||||
background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
|
||||
background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-danger {
|
||||
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
|
||||
background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);
|
||||
background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));
|
||||
background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
|
||||
background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-striped {
|
||||
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
|
||||
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
|
||||
background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
|
||||
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
}
|
||||
.list-group {
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
}
|
||||
.list-group-item.active,
|
||||
.list-group-item.active:hover,
|
||||
.list-group-item.active:focus {
|
||||
text-shadow: 0 -1px 0 #286090;
|
||||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a));
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #2b669a;
|
||||
@@ -522,66 +522,66 @@ fieldset[disabled] .btn-danger.active {
|
||||
text-shadow: none;
|
||||
}
|
||||
.panel {
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.panel-default > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
|
||||
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-primary > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-success > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
|
||||
background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
|
||||
background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));
|
||||
background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
|
||||
background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-info > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
|
||||
background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
|
||||
background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));
|
||||
background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
|
||||
background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-warning > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
|
||||
background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
|
||||
background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));
|
||||
background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
|
||||
background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-danger > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
|
||||
background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
|
||||
background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));
|
||||
background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
|
||||
background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.well {
|
||||
background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
|
||||
background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
|
||||
background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));
|
||||
background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
|
||||
background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dcdcdc;
|
||||
-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
|
||||
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
|
||||
-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-theme.css.map */
|
||||
/*# sourceMappingURL=bootstrap-theme.css.map */
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
985
inst/www/shared/bootstrap/css/bootstrap.css
vendored
985
inst/www/shared/bootstrap/css/bootstrap.css
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
397
inst/www/shared/bootstrap/js/bootstrap.js
vendored
397
inst/www/shared/bootstrap/js/bootstrap.js
vendored
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* Bootstrap v3.3.7 (http://getbootstrap.com)
|
||||
* Copyright 2011-2016 Twitter, Inc.
|
||||
* Bootstrap v3.4.1 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2019 Twitter, Inc.
|
||||
* Licensed under the MIT license
|
||||
*/
|
||||
|
||||
@@ -17,10 +17,10 @@ if (typeof jQuery === 'undefined') {
|
||||
}(jQuery);
|
||||
|
||||
/* ========================================================================
|
||||
* Bootstrap: transition.js v3.3.7
|
||||
* http://getbootstrap.com/javascript/#transitions
|
||||
* Bootstrap: transition.js v3.4.1
|
||||
* https://getbootstrap.com/docs/3.4/javascript/#transitions
|
||||
* ========================================================================
|
||||
* Copyright 2011-2016 Twitter, Inc.
|
||||
* Copyright 2011-2019 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* ======================================================================== */
|
||||
|
||||
@@ -28,7 +28,7 @@ if (typeof jQuery === 'undefined') {
|
||||
+function ($) {
|
||||
'use strict';
|
||||
|
||||
// CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
|
||||
// CSS TRANSITION SUPPORT (Shoutout: https://modernizr.com/)
|
||||
// ============================================================
|
||||
|
||||
function transitionEnd() {
|
||||
@@ -50,7 +50,7 @@ if (typeof jQuery === 'undefined') {
|
||||
return false // explicit for ie8 ( ._.)
|
||||
}
|
||||
|
||||
// http://blog.alexmaccaw.com/css-transitions
|
||||
// https://blog.alexmaccaw.com/css-transitions
|
||||
$.fn.emulateTransitionEnd = function (duration) {
|
||||
var called = false
|
||||
var $el = this
|
||||
@@ -77,10 +77,10 @@ if (typeof jQuery === 'undefined') {
|
||||
}(jQuery);
|
||||
|
||||
/* ========================================================================
|
||||
* Bootstrap: alert.js v3.3.7
|
||||
* http://getbootstrap.com/javascript/#alerts
|
||||
* Bootstrap: alert.js v3.4.1
|
||||
* https://getbootstrap.com/docs/3.4/javascript/#alerts
|
||||
* ========================================================================
|
||||
* Copyright 2011-2016 Twitter, Inc.
|
||||
* Copyright 2011-2019 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* ======================================================================== */
|
||||
|
||||
@@ -96,7 +96,7 @@ if (typeof jQuery === 'undefined') {
|
||||
$(el).on('click', dismiss, this.close)
|
||||
}
|
||||
|
||||
Alert.VERSION = '3.3.7'
|
||||
Alert.VERSION = '3.4.1'
|
||||
|
||||
Alert.TRANSITION_DURATION = 150
|
||||
|
||||
@@ -109,7 +109,8 @@ if (typeof jQuery === 'undefined') {
|
||||
selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
|
||||
}
|
||||
|
||||
var $parent = $(selector === '#' ? [] : selector)
|
||||
selector = selector === '#' ? [] : selector
|
||||
var $parent = $(document).find(selector)
|
||||
|
||||
if (e) e.preventDefault()
|
||||
|
||||
@@ -172,10 +173,10 @@ if (typeof jQuery === 'undefined') {
|
||||
}(jQuery);
|
||||
|
||||
/* ========================================================================
|
||||
* Bootstrap: button.js v3.3.7
|
||||
* http://getbootstrap.com/javascript/#buttons
|
||||
* Bootstrap: button.js v3.4.1
|
||||
* https://getbootstrap.com/docs/3.4/javascript/#buttons
|
||||
* ========================================================================
|
||||
* Copyright 2011-2016 Twitter, Inc.
|
||||
* Copyright 2011-2019 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* ======================================================================== */
|
||||
|
||||
@@ -192,7 +193,7 @@ if (typeof jQuery === 'undefined') {
|
||||
this.isLoading = false
|
||||
}
|
||||
|
||||
Button.VERSION = '3.3.7'
|
||||
Button.VERSION = '3.4.1'
|
||||
|
||||
Button.DEFAULTS = {
|
||||
loadingText: 'loading...'
|
||||
@@ -298,10 +299,10 @@ if (typeof jQuery === 'undefined') {
|
||||
}(jQuery);
|
||||
|
||||
/* ========================================================================
|
||||
* Bootstrap: carousel.js v3.3.7
|
||||
* http://getbootstrap.com/javascript/#carousel
|
||||
* Bootstrap: carousel.js v3.4.1
|
||||
* https://getbootstrap.com/docs/3.4/javascript/#carousel
|
||||
* ========================================================================
|
||||
* Copyright 2011-2016 Twitter, Inc.
|
||||
* Copyright 2011-2019 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* ======================================================================== */
|
||||
|
||||
@@ -329,7 +330,7 @@ if (typeof jQuery === 'undefined') {
|
||||
.on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
|
||||
}
|
||||
|
||||
Carousel.VERSION = '3.3.7'
|
||||
Carousel.VERSION = '3.4.1'
|
||||
|
||||
Carousel.TRANSITION_DURATION = 600
|
||||
|
||||
@@ -443,7 +444,9 @@ if (typeof jQuery === 'undefined') {
|
||||
var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
|
||||
if ($.support.transition && this.$element.hasClass('slide')) {
|
||||
$next.addClass(type)
|
||||
$next[0].offsetWidth // force reflow
|
||||
if (typeof $next === 'object' && $next.length) {
|
||||
$next[0].offsetWidth // force reflow
|
||||
}
|
||||
$active.addClass(direction)
|
||||
$next.addClass(direction)
|
||||
$active
|
||||
@@ -505,10 +508,17 @@ if (typeof jQuery === 'undefined') {
|
||||
// =================
|
||||
|
||||
var clickHandler = function (e) {
|
||||
var href
|
||||
var $this = $(this)
|
||||
var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
|
||||
var href = $this.attr('href')
|
||||
if (href) {
|
||||
href = href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
|
||||
}
|
||||
|
||||
var target = $this.attr('data-target') || href
|
||||
var $target = $(document).find(target)
|
||||
|
||||
if (!$target.hasClass('carousel')) return
|
||||
|
||||
var options = $.extend({}, $target.data(), $this.data())
|
||||
var slideIndex = $this.attr('data-slide-to')
|
||||
if (slideIndex) options.interval = false
|
||||
@@ -536,10 +546,10 @@ if (typeof jQuery === 'undefined') {
|
||||
}(jQuery);
|
||||
|
||||
/* ========================================================================
|
||||
* Bootstrap: collapse.js v3.3.7
|
||||
* http://getbootstrap.com/javascript/#collapse
|
||||
* Bootstrap: collapse.js v3.4.1
|
||||
* https://getbootstrap.com/docs/3.4/javascript/#collapse
|
||||
* ========================================================================
|
||||
* Copyright 2011-2016 Twitter, Inc.
|
||||
* Copyright 2011-2019 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* ======================================================================== */
|
||||
|
||||
@@ -567,7 +577,7 @@ if (typeof jQuery === 'undefined') {
|
||||
if (this.options.toggle) this.toggle()
|
||||
}
|
||||
|
||||
Collapse.VERSION = '3.3.7'
|
||||
Collapse.VERSION = '3.4.1'
|
||||
|
||||
Collapse.TRANSITION_DURATION = 350
|
||||
|
||||
@@ -674,7 +684,7 @@ if (typeof jQuery === 'undefined') {
|
||||
}
|
||||
|
||||
Collapse.prototype.getParent = function () {
|
||||
return $(this.options.parent)
|
||||
return $(document).find(this.options.parent)
|
||||
.find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
|
||||
.each($.proxy(function (i, element) {
|
||||
var $element = $(element)
|
||||
@@ -697,7 +707,7 @@ if (typeof jQuery === 'undefined') {
|
||||
var target = $trigger.attr('data-target')
|
||||
|| (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
|
||||
|
||||
return $(target)
|
||||
return $(document).find(target)
|
||||
}
|
||||
|
||||
|
||||
@@ -749,10 +759,10 @@ if (typeof jQuery === 'undefined') {
|
||||
}(jQuery);
|
||||
|
||||
/* ========================================================================
|
||||
* Bootstrap: dropdown.js v3.3.7
|
||||
* http://getbootstrap.com/javascript/#dropdowns
|
||||
* Bootstrap: dropdown.js v3.4.1
|
||||
* https://getbootstrap.com/docs/3.4/javascript/#dropdowns
|
||||
* ========================================================================
|
||||
* Copyright 2011-2016 Twitter, Inc.
|
||||
* Copyright 2011-2019 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* ======================================================================== */
|
||||
|
||||
@@ -769,7 +779,7 @@ if (typeof jQuery === 'undefined') {
|
||||
$(element).on('click.bs.dropdown', this.toggle)
|
||||
}
|
||||
|
||||
Dropdown.VERSION = '3.3.7'
|
||||
Dropdown.VERSION = '3.4.1'
|
||||
|
||||
function getParent($this) {
|
||||
var selector = $this.attr('data-target')
|
||||
@@ -779,7 +789,7 @@ if (typeof jQuery === 'undefined') {
|
||||
selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
|
||||
}
|
||||
|
||||
var $parent = selector && $(selector)
|
||||
var $parent = selector !== '#' ? $(document).find(selector) : null
|
||||
|
||||
return $parent && $parent.length ? $parent : $this.parent()
|
||||
}
|
||||
@@ -915,10 +925,10 @@ if (typeof jQuery === 'undefined') {
|
||||
}(jQuery);
|
||||
|
||||
/* ========================================================================
|
||||
* Bootstrap: modal.js v3.3.7
|
||||
* http://getbootstrap.com/javascript/#modals
|
||||
* Bootstrap: modal.js v3.4.1
|
||||
* https://getbootstrap.com/docs/3.4/javascript/#modals
|
||||
* ========================================================================
|
||||
* Copyright 2011-2016 Twitter, Inc.
|
||||
* Copyright 2011-2019 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* ======================================================================== */
|
||||
|
||||
@@ -930,15 +940,16 @@ if (typeof jQuery === 'undefined') {
|
||||
// ======================
|
||||
|
||||
var Modal = function (element, options) {
|
||||
this.options = options
|
||||
this.$body = $(document.body)
|
||||
this.$element = $(element)
|
||||
this.$dialog = this.$element.find('.modal-dialog')
|
||||
this.$backdrop = null
|
||||
this.isShown = null
|
||||
this.originalBodyPad = null
|
||||
this.scrollbarWidth = 0
|
||||
this.options = options
|
||||
this.$body = $(document.body)
|
||||
this.$element = $(element)
|
||||
this.$dialog = this.$element.find('.modal-dialog')
|
||||
this.$backdrop = null
|
||||
this.isShown = null
|
||||
this.originalBodyPad = null
|
||||
this.scrollbarWidth = 0
|
||||
this.ignoreBackdropClick = false
|
||||
this.fixedContent = '.navbar-fixed-top, .navbar-fixed-bottom'
|
||||
|
||||
if (this.options.remote) {
|
||||
this.$element
|
||||
@@ -949,7 +960,7 @@ if (typeof jQuery === 'undefined') {
|
||||
}
|
||||
}
|
||||
|
||||
Modal.VERSION = '3.3.7'
|
||||
Modal.VERSION = '3.4.1'
|
||||
|
||||
Modal.TRANSITION_DURATION = 300
|
||||
Modal.BACKDROP_TRANSITION_DURATION = 150
|
||||
@@ -966,7 +977,7 @@ if (typeof jQuery === 'undefined') {
|
||||
|
||||
Modal.prototype.show = function (_relatedTarget) {
|
||||
var that = this
|
||||
var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
|
||||
var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
|
||||
|
||||
this.$element.trigger(e)
|
||||
|
||||
@@ -1057,8 +1068,8 @@ if (typeof jQuery === 'undefined') {
|
||||
.off('focusin.bs.modal') // guard against infinite focus loop
|
||||
.on('focusin.bs.modal', $.proxy(function (e) {
|
||||
if (document !== e.target &&
|
||||
this.$element[0] !== e.target &&
|
||||
!this.$element.has(e.target).length) {
|
||||
this.$element[0] !== e.target &&
|
||||
!this.$element.has(e.target).length) {
|
||||
this.$element.trigger('focus')
|
||||
}
|
||||
}, this))
|
||||
@@ -1160,7 +1171,7 @@ if (typeof jQuery === 'undefined') {
|
||||
var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
|
||||
|
||||
this.$element.css({
|
||||
paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
|
||||
paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
|
||||
paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
|
||||
})
|
||||
}
|
||||
@@ -1185,11 +1196,26 @@ if (typeof jQuery === 'undefined') {
|
||||
Modal.prototype.setScrollbar = function () {
|
||||
var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
|
||||
this.originalBodyPad = document.body.style.paddingRight || ''
|
||||
if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
|
||||
var scrollbarWidth = this.scrollbarWidth
|
||||
if (this.bodyIsOverflowing) {
|
||||
this.$body.css('padding-right', bodyPad + scrollbarWidth)
|
||||
$(this.fixedContent).each(function (index, element) {
|
||||
var actualPadding = element.style.paddingRight
|
||||
var calculatedPadding = $(element).css('padding-right')
|
||||
$(element)
|
||||
.data('padding-right', actualPadding)
|
||||
.css('padding-right', parseFloat(calculatedPadding) + scrollbarWidth + 'px')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Modal.prototype.resetScrollbar = function () {
|
||||
this.$body.css('padding-right', this.originalBodyPad)
|
||||
$(this.fixedContent).each(function (index, element) {
|
||||
var padding = $(element).data('padding-right')
|
||||
$(element).removeData('padding-right')
|
||||
element.style.paddingRight = padding ? padding : ''
|
||||
})
|
||||
}
|
||||
|
||||
Modal.prototype.measureScrollbar = function () { // thx walsh
|
||||
@@ -1207,8 +1233,8 @@ if (typeof jQuery === 'undefined') {
|
||||
|
||||
function Plugin(option, _relatedTarget) {
|
||||
return this.each(function () {
|
||||
var $this = $(this)
|
||||
var data = $this.data('bs.modal')
|
||||
var $this = $(this)
|
||||
var data = $this.data('bs.modal')
|
||||
var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
|
||||
|
||||
if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
|
||||
@@ -1219,7 +1245,7 @@ if (typeof jQuery === 'undefined') {
|
||||
|
||||
var old = $.fn.modal
|
||||
|
||||
$.fn.modal = Plugin
|
||||
$.fn.modal = Plugin
|
||||
$.fn.modal.Constructor = Modal
|
||||
|
||||
|
||||
@@ -1236,10 +1262,13 @@ if (typeof jQuery === 'undefined') {
|
||||
// ==============
|
||||
|
||||
$(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
|
||||
var $this = $(this)
|
||||
var href = $this.attr('href')
|
||||
var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
|
||||
var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
|
||||
var $this = $(this)
|
||||
var href = $this.attr('href')
|
||||
var target = $this.attr('data-target') ||
|
||||
(href && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
|
||||
|
||||
var $target = $(document).find(target)
|
||||
var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
|
||||
|
||||
if ($this.is('a')) e.preventDefault()
|
||||
|
||||
@@ -1255,18 +1284,148 @@ if (typeof jQuery === 'undefined') {
|
||||
}(jQuery);
|
||||
|
||||
/* ========================================================================
|
||||
* Bootstrap: tooltip.js v3.3.7
|
||||
* http://getbootstrap.com/javascript/#tooltip
|
||||
* Bootstrap: tooltip.js v3.4.1
|
||||
* https://getbootstrap.com/docs/3.4/javascript/#tooltip
|
||||
* Inspired by the original jQuery.tipsy by Jason Frame
|
||||
* ========================================================================
|
||||
* Copyright 2011-2016 Twitter, Inc.
|
||||
* Copyright 2011-2019 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* ======================================================================== */
|
||||
|
||||
|
||||
+function ($) {
|
||||
'use strict';
|
||||
|
||||
var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn']
|
||||
|
||||
var uriAttrs = [
|
||||
'background',
|
||||
'cite',
|
||||
'href',
|
||||
'itemtype',
|
||||
'longdesc',
|
||||
'poster',
|
||||
'src',
|
||||
'xlink:href'
|
||||
]
|
||||
|
||||
var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
|
||||
|
||||
var DefaultWhitelist = {
|
||||
// Global attributes allowed on any supplied element below.
|
||||
'*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
|
||||
a: ['target', 'href', 'title', 'rel'],
|
||||
area: [],
|
||||
b: [],
|
||||
br: [],
|
||||
col: [],
|
||||
code: [],
|
||||
div: [],
|
||||
em: [],
|
||||
hr: [],
|
||||
h1: [],
|
||||
h2: [],
|
||||
h3: [],
|
||||
h4: [],
|
||||
h5: [],
|
||||
h6: [],
|
||||
i: [],
|
||||
img: ['src', 'alt', 'title', 'width', 'height'],
|
||||
li: [],
|
||||
ol: [],
|
||||
p: [],
|
||||
pre: [],
|
||||
s: [],
|
||||
small: [],
|
||||
span: [],
|
||||
sub: [],
|
||||
sup: [],
|
||||
strong: [],
|
||||
u: [],
|
||||
ul: []
|
||||
}
|
||||
|
||||
/**
|
||||
* A pattern that recognizes a commonly useful subset of URLs that are safe.
|
||||
*
|
||||
* Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
|
||||
*/
|
||||
var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi
|
||||
|
||||
/**
|
||||
* A pattern that matches safe data URLs. Only matches image, video and audio types.
|
||||
*
|
||||
* Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
|
||||
*/
|
||||
var DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i
|
||||
|
||||
function allowedAttribute(attr, allowedAttributeList) {
|
||||
var attrName = attr.nodeName.toLowerCase()
|
||||
|
||||
if ($.inArray(attrName, allowedAttributeList) !== -1) {
|
||||
if ($.inArray(attrName, uriAttrs) !== -1) {
|
||||
return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
var regExp = $(allowedAttributeList).filter(function (index, value) {
|
||||
return value instanceof RegExp
|
||||
})
|
||||
|
||||
// Check if a regular expression validates the attribute.
|
||||
for (var i = 0, l = regExp.length; i < l; i++) {
|
||||
if (attrName.match(regExp[i])) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
|
||||
if (unsafeHtml.length === 0) {
|
||||
return unsafeHtml
|
||||
}
|
||||
|
||||
if (sanitizeFn && typeof sanitizeFn === 'function') {
|
||||
return sanitizeFn(unsafeHtml)
|
||||
}
|
||||
|
||||
// IE 8 and below don't support createHTMLDocument
|
||||
if (!document.implementation || !document.implementation.createHTMLDocument) {
|
||||
return unsafeHtml
|
||||
}
|
||||
|
||||
var createdDocument = document.implementation.createHTMLDocument('sanitization')
|
||||
createdDocument.body.innerHTML = unsafeHtml
|
||||
|
||||
var whitelistKeys = $.map(whiteList, function (el, i) { return i })
|
||||
var elements = $(createdDocument.body).find('*')
|
||||
|
||||
for (var i = 0, len = elements.length; i < len; i++) {
|
||||
var el = elements[i]
|
||||
var elName = el.nodeName.toLowerCase()
|
||||
|
||||
if ($.inArray(elName, whitelistKeys) === -1) {
|
||||
el.parentNode.removeChild(el)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
var attributeList = $.map(el.attributes, function (el) { return el })
|
||||
var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || [])
|
||||
|
||||
for (var j = 0, len2 = attributeList.length; j < len2; j++) {
|
||||
if (!allowedAttribute(attributeList[j], whitelistedAttributes)) {
|
||||
el.removeAttribute(attributeList[j].nodeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return createdDocument.body.innerHTML
|
||||
}
|
||||
|
||||
// TOOLTIP PUBLIC CLASS DEFINITION
|
||||
// ===============================
|
||||
|
||||
@@ -1282,7 +1441,7 @@ if (typeof jQuery === 'undefined') {
|
||||
this.init('tooltip', element, options)
|
||||
}
|
||||
|
||||
Tooltip.VERSION = '3.3.7'
|
||||
Tooltip.VERSION = '3.4.1'
|
||||
|
||||
Tooltip.TRANSITION_DURATION = 150
|
||||
|
||||
@@ -1299,7 +1458,10 @@ if (typeof jQuery === 'undefined') {
|
||||
viewport: {
|
||||
selector: 'body',
|
||||
padding: 0
|
||||
}
|
||||
},
|
||||
sanitize : true,
|
||||
sanitizeFn : null,
|
||||
whiteList : DefaultWhitelist
|
||||
}
|
||||
|
||||
Tooltip.prototype.init = function (type, element, options) {
|
||||
@@ -1307,7 +1469,7 @@ if (typeof jQuery === 'undefined') {
|
||||
this.type = type
|
||||
this.$element = $(element)
|
||||
this.options = this.getOptions(options)
|
||||
this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
|
||||
this.$viewport = this.options.viewport && $(document).find($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
|
||||
this.inState = { click: false, hover: false, focus: false }
|
||||
|
||||
if (this.$element[0] instanceof document.constructor && !this.options.selector) {
|
||||
@@ -1340,7 +1502,15 @@ if (typeof jQuery === 'undefined') {
|
||||
}
|
||||
|
||||
Tooltip.prototype.getOptions = function (options) {
|
||||
options = $.extend({}, this.getDefaults(), this.$element.data(), options)
|
||||
var dataAttributes = this.$element.data()
|
||||
|
||||
for (var dataAttr in dataAttributes) {
|
||||
if (dataAttributes.hasOwnProperty(dataAttr) && $.inArray(dataAttr, DISALLOWED_ATTRIBUTES) !== -1) {
|
||||
delete dataAttributes[dataAttr]
|
||||
}
|
||||
}
|
||||
|
||||
options = $.extend({}, this.getDefaults(), dataAttributes, options)
|
||||
|
||||
if (options.delay && typeof options.delay == 'number') {
|
||||
options.delay = {
|
||||
@@ -1349,6 +1519,10 @@ if (typeof jQuery === 'undefined') {
|
||||
}
|
||||
}
|
||||
|
||||
if (options.sanitize) {
|
||||
options.template = sanitizeHtml(options.template, options.whiteList, options.sanitizeFn)
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
@@ -1460,7 +1634,7 @@ if (typeof jQuery === 'undefined') {
|
||||
.addClass(placement)
|
||||
.data('bs.' + this.type, this)
|
||||
|
||||
this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
|
||||
this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element)
|
||||
this.$element.trigger('inserted.bs.' + this.type)
|
||||
|
||||
var pos = this.getPosition()
|
||||
@@ -1562,7 +1736,16 @@ if (typeof jQuery === 'undefined') {
|
||||
var $tip = this.tip()
|
||||
var title = this.getTitle()
|
||||
|
||||
$tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
|
||||
if (this.options.html) {
|
||||
if (this.options.sanitize) {
|
||||
title = sanitizeHtml(title, this.options.whiteList, this.options.sanitizeFn)
|
||||
}
|
||||
|
||||
$tip.find('.tooltip-inner').html(title)
|
||||
} else {
|
||||
$tip.find('.tooltip-inner').text(title)
|
||||
}
|
||||
|
||||
$tip.removeClass('fade in top bottom left right')
|
||||
}
|
||||
|
||||
@@ -1743,6 +1926,9 @@ if (typeof jQuery === 'undefined') {
|
||||
})
|
||||
}
|
||||
|
||||
Tooltip.prototype.sanitizeHtml = function (unsafeHtml) {
|
||||
return sanitizeHtml(unsafeHtml, this.options.whiteList, this.options.sanitizeFn)
|
||||
}
|
||||
|
||||
// TOOLTIP PLUGIN DEFINITION
|
||||
// =========================
|
||||
@@ -1776,10 +1962,10 @@ if (typeof jQuery === 'undefined') {
|
||||
}(jQuery);
|
||||
|
||||
/* ========================================================================
|
||||
* Bootstrap: popover.js v3.3.7
|
||||
* http://getbootstrap.com/javascript/#popovers
|
||||
* Bootstrap: popover.js v3.4.1
|
||||
* https://getbootstrap.com/docs/3.4/javascript/#popovers
|
||||
* ========================================================================
|
||||
* Copyright 2011-2016 Twitter, Inc.
|
||||
* Copyright 2011-2019 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* ======================================================================== */
|
||||
|
||||
@@ -1796,7 +1982,7 @@ if (typeof jQuery === 'undefined') {
|
||||
|
||||
if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
|
||||
|
||||
Popover.VERSION = '3.3.7'
|
||||
Popover.VERSION = '3.4.1'
|
||||
|
||||
Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
|
||||
placement: 'right',
|
||||
@@ -1822,10 +2008,25 @@ if (typeof jQuery === 'undefined') {
|
||||
var title = this.getTitle()
|
||||
var content = this.getContent()
|
||||
|
||||
$tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
|
||||
$tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events
|
||||
this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
|
||||
](content)
|
||||
if (this.options.html) {
|
||||
var typeContent = typeof content
|
||||
|
||||
if (this.options.sanitize) {
|
||||
title = this.sanitizeHtml(title)
|
||||
|
||||
if (typeContent === 'string') {
|
||||
content = this.sanitizeHtml(content)
|
||||
}
|
||||
}
|
||||
|
||||
$tip.find('.popover-title').html(title)
|
||||
$tip.find('.popover-content').children().detach().end()[
|
||||
typeContent === 'string' ? 'html' : 'append'
|
||||
](content)
|
||||
} else {
|
||||
$tip.find('.popover-title').text(title)
|
||||
$tip.find('.popover-content').children().detach().end().text(content)
|
||||
}
|
||||
|
||||
$tip.removeClass('fade top bottom left right in')
|
||||
|
||||
@@ -1844,8 +2045,8 @@ if (typeof jQuery === 'undefined') {
|
||||
|
||||
return $e.attr('data-content')
|
||||
|| (typeof o.content == 'function' ?
|
||||
o.content.call($e[0]) :
|
||||
o.content)
|
||||
o.content.call($e[0]) :
|
||||
o.content)
|
||||
}
|
||||
|
||||
Popover.prototype.arrow = function () {
|
||||
@@ -1885,10 +2086,10 @@ if (typeof jQuery === 'undefined') {
|
||||
}(jQuery);
|
||||
|
||||
/* ========================================================================
|
||||
* Bootstrap: scrollspy.js v3.3.7
|
||||
* http://getbootstrap.com/javascript/#scrollspy
|
||||
* Bootstrap: scrollspy.js v3.4.1
|
||||
* https://getbootstrap.com/docs/3.4/javascript/#scrollspy
|
||||
* ========================================================================
|
||||
* Copyright 2011-2016 Twitter, Inc.
|
||||
* Copyright 2011-2019 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* ======================================================================== */
|
||||
|
||||
@@ -1914,7 +2115,7 @@ if (typeof jQuery === 'undefined') {
|
||||
this.process()
|
||||
}
|
||||
|
||||
ScrollSpy.VERSION = '3.3.7'
|
||||
ScrollSpy.VERSION = '3.4.1'
|
||||
|
||||
ScrollSpy.DEFAULTS = {
|
||||
offset: 10
|
||||
@@ -2058,10 +2259,10 @@ if (typeof jQuery === 'undefined') {
|
||||
}(jQuery);
|
||||
|
||||
/* ========================================================================
|
||||
* Bootstrap: tab.js v3.3.7
|
||||
* http://getbootstrap.com/javascript/#tabs
|
||||
* Bootstrap: tab.js v3.4.1
|
||||
* https://getbootstrap.com/docs/3.4/javascript/#tabs
|
||||
* ========================================================================
|
||||
* Copyright 2011-2016 Twitter, Inc.
|
||||
* Copyright 2011-2019 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* ======================================================================== */
|
||||
|
||||
@@ -2078,7 +2279,7 @@ if (typeof jQuery === 'undefined') {
|
||||
// jscs:enable requireDollarBeforejQueryAssignment
|
||||
}
|
||||
|
||||
Tab.VERSION = '3.3.7'
|
||||
Tab.VERSION = '3.4.1'
|
||||
|
||||
Tab.TRANSITION_DURATION = 150
|
||||
|
||||
@@ -2107,7 +2308,7 @@ if (typeof jQuery === 'undefined') {
|
||||
|
||||
if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
|
||||
|
||||
var $target = $(selector)
|
||||
var $target = $(document).find(selector)
|
||||
|
||||
this.activate($this.closest('li'), $ul)
|
||||
this.activate($target, $target.parent(), function () {
|
||||
@@ -2132,15 +2333,15 @@ if (typeof jQuery === 'undefined') {
|
||||
$active
|
||||
.removeClass('active')
|
||||
.find('> .dropdown-menu > .active')
|
||||
.removeClass('active')
|
||||
.removeClass('active')
|
||||
.end()
|
||||
.find('[data-toggle="tab"]')
|
||||
.attr('aria-expanded', false)
|
||||
.attr('aria-expanded', false)
|
||||
|
||||
element
|
||||
.addClass('active')
|
||||
.find('[data-toggle="tab"]')
|
||||
.attr('aria-expanded', true)
|
||||
.attr('aria-expanded', true)
|
||||
|
||||
if (transition) {
|
||||
element[0].offsetWidth // reflow for transition
|
||||
@@ -2152,10 +2353,10 @@ if (typeof jQuery === 'undefined') {
|
||||
if (element.parent('.dropdown-menu').length) {
|
||||
element
|
||||
.closest('li.dropdown')
|
||||
.addClass('active')
|
||||
.addClass('active')
|
||||
.end()
|
||||
.find('[data-toggle="tab"]')
|
||||
.attr('aria-expanded', true)
|
||||
.attr('aria-expanded', true)
|
||||
}
|
||||
|
||||
callback && callback()
|
||||
@@ -2214,10 +2415,10 @@ if (typeof jQuery === 'undefined') {
|
||||
}(jQuery);
|
||||
|
||||
/* ========================================================================
|
||||
* Bootstrap: affix.js v3.3.7
|
||||
* http://getbootstrap.com/javascript/#affix
|
||||
* Bootstrap: affix.js v3.4.1
|
||||
* https://getbootstrap.com/docs/3.4/javascript/#affix
|
||||
* ========================================================================
|
||||
* Copyright 2011-2016 Twitter, Inc.
|
||||
* Copyright 2011-2019 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* ======================================================================== */
|
||||
|
||||
@@ -2231,7 +2432,9 @@ if (typeof jQuery === 'undefined') {
|
||||
var Affix = function (element, options) {
|
||||
this.options = $.extend({}, Affix.DEFAULTS, options)
|
||||
|
||||
this.$target = $(this.options.target)
|
||||
var target = this.options.target === Affix.DEFAULTS.target ? $(this.options.target) : $(document).find(this.options.target)
|
||||
|
||||
this.$target = target
|
||||
.on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
|
||||
.on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
|
||||
|
||||
@@ -2243,7 +2446,7 @@ if (typeof jQuery === 'undefined') {
|
||||
this.checkPosition()
|
||||
}
|
||||
|
||||
Affix.VERSION = '3.3.7'
|
||||
Affix.VERSION = '3.4.1'
|
||||
|
||||
Affix.RESET = 'affix affix-top affix-bottom'
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1723,7 +1723,12 @@
|
||||
if (this.has_tab_index) {
|
||||
this.$cache.input.prop("tabindex", -1);
|
||||
} else {
|
||||
this.$cache.input.removeProp("tabindex");
|
||||
try {
|
||||
this.$cache.input.removeProp("tabindex");
|
||||
} catch(e) {
|
||||
// Do nothing (PhantomJS can throw an error with the
|
||||
// above, #2587)
|
||||
}
|
||||
}
|
||||
|
||||
this.has_tab_index = !this.has_tab_index;
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -6,10 +6,10 @@ Michael Geary <mike@geary.com>
|
||||
Stefan Petre <stefan.petre@gmail.com>
|
||||
Yehuda Katz <wycats@gmail.com>
|
||||
Corey Jewett <cj@syntheticplayground.com>
|
||||
Klaus Hartl <klaus.hartl@googlemail.com>
|
||||
Klaus Hartl <klaus.hartl@gmail.com>
|
||||
Franck Marcia <franck.marcia@gmail.com>
|
||||
Jörn Zaefferer <joern.zaefferer@gmail.com>
|
||||
Paul Bakaus <paul.bakaus@googlemail.com>
|
||||
Paul Bakaus <paul.bakaus@gmail.com>
|
||||
Brandon Aaron <brandon.aaron@gmail.com>
|
||||
Mike Alsup <malsup@gmail.com>
|
||||
Dave Methvin <dave.methvin@gmail.com>
|
||||
@@ -47,7 +47,7 @@ Matt Curry <matt@pseudocoder.com>
|
||||
Michael Monteleone <michael@michaelmonteleone.net>
|
||||
Noah Sloan <noah.sloan@gmail.com>
|
||||
Tom Viner <github@viner.tv>
|
||||
Douglas Neiner <doug@pixelgraphics.us>
|
||||
Douglas Neiner <doug@dougneiner.com>
|
||||
Adam J. Sontag <ajpiano@ajpiano.com>
|
||||
Dave Reed <dareed@microsoft.com>
|
||||
Ralph Whitbeck <ralph.whitbeck@gmail.com>
|
||||
@@ -57,7 +57,7 @@ J. Ryan Stinnett <jryans@gmail.com>
|
||||
unknown <Igen005@.upcorp.ad.uprr.com>
|
||||
temp01 <temp01irc@gmail.com>
|
||||
Heungsub Lee <h@subl.ee>
|
||||
Colin Snover <colin@alpha.zetafleet.com>
|
||||
Colin Snover <github.com@zetafleet.com>
|
||||
Ryan W Tenney <ryan@10e.us>
|
||||
Pinhook <contact@pinhooklabs.com>
|
||||
Ron Otten <r.j.g.otten@gmail.com>
|
||||
@@ -69,7 +69,7 @@ Henri Wiechers <hwiechers@gmail.com>
|
||||
Russell Holbrook <russell.holbrook@patch.com>
|
||||
Julian Aubourg <aubourg.julian@gmail.com>
|
||||
Gianni Alessandro Chiappetta <gianni@runlevel6.org>
|
||||
Scott Jehl <scott@scottjehl.com>
|
||||
Scott Jehl <scottjehl@gmail.com>
|
||||
James Burke <jrburke@gmail.com>
|
||||
Jonas Pfenniger <jonas@pfenniger.name>
|
||||
Xavi Ramirez <xavi.rmz@gmail.com>
|
||||
@@ -77,11 +77,11 @@ Jared Grippe <jared@deadlyicon.com>
|
||||
Sylvester Keil <sylvester@keil.or.at>
|
||||
Brandon Sterne <bsterne@mozilla.com>
|
||||
Mathias Bynens <mathias@qiwi.be>
|
||||
Timmy Willison <timmywillisn@gmail.com>
|
||||
Corey Frang <gnarf@gnarf.net>
|
||||
Timmy Willison <4timmywil@gmail.com>
|
||||
Corey Frang <gnarf37@gmail.com>
|
||||
Digitalxero <digitalxero>
|
||||
Anton Kovalyov <anton@kovalyov.net>
|
||||
David Murdoch <musicisair@yahoo.com>
|
||||
David Murdoch <david@davidmurdoch.com>
|
||||
Josh Varner <josh.varner@gmail.com>
|
||||
Charles McNulty <cmcnulty@kznf.com>
|
||||
Jordan Boesch <jboesch26@gmail.com>
|
||||
@@ -139,7 +139,7 @@ Chris Faulkner <thefaulkner@gmail.com>
|
||||
Elijah Manor <elijah.manor@gmail.com>
|
||||
Daniel Chatfield <chatfielddaniel@gmail.com>
|
||||
Nikita Govorov <nikita.govorov@gmail.com>
|
||||
Wesley Walser <wwalser@atlassian.com>
|
||||
Wesley Walser <waw325@gmail.com>
|
||||
Mike Pennisi <mike@mikepennisi.com>
|
||||
Markus Staab <markus.staab@redaxo.de>
|
||||
Dave Riddle <david@joyvuu.com>
|
||||
@@ -170,6 +170,8 @@ Paul Ramos <paul.b.ramos@gmail.com>
|
||||
Rod Vagg <rod@vagg.org>
|
||||
Bennett Sorbo <bsorbo@gmail.com>
|
||||
Sebastian Burkhard <sebi.burkhard@gmail.com>
|
||||
Zachary Adam Kaplan <razic@viralkitty.com>
|
||||
nanto_vi <nanto@moon.email.ne.jp>
|
||||
nanto <nanto@moon.email.ne.jp>
|
||||
Danil Somsikov <danilasomsikov@gmail.com>
|
||||
Ryunosuke SATO <tricknotes.rs@gmail.com>
|
||||
@@ -177,62 +179,70 @@ Jean Boussier <jean.boussier@gmail.com>
|
||||
Adam Coulombe <me@adam.co>
|
||||
Andrew Plummer <plummer.andrew@gmail.com>
|
||||
Mark Raddatz <mraddatz@gmail.com>
|
||||
Dmitry Gusev <dmitry.gusev@gmail.com>
|
||||
Michał Gołębiowski <m.goleb@gmail.com>
|
||||
Isaac Z. Schlueter <i@izs.me>
|
||||
Karl Sieburg <ksieburg@yahoo.com>
|
||||
Pascal Borreli <pascal@borreli.com>
|
||||
Nguyen Phuc Lam <ruado1987@gmail.com>
|
||||
Dmitry Gusev <dmitry.gusev@gmail.com>
|
||||
Michał Gołębiowski-Owczarek <m.goleb@gmail.com>
|
||||
Li Xudong <istonelee@gmail.com>
|
||||
Steven Benner <admin@stevenbenner.com>
|
||||
Tom H Fuertes <tomfuertes@gmail.com>
|
||||
Brandon Johnson <bjohn465+github@gmail.com>
|
||||
Renato Oliveira dos Santos <ros3@cin.ufpe.br>
|
||||
ros3cin <ros3@cin.ufpe.br>
|
||||
Jason Bedard <jason+jquery@jbedard.ca>
|
||||
Kyle Robinson Young <kyle@dontkry.com>
|
||||
Renato Oliveira dos Santos <ros3@cin.ufpe.br>
|
||||
Chris Talkington <chris@talkingtontech.com>
|
||||
Eddie Monge <eddie@eddiemonge.com>
|
||||
Terry Jones <terry@jon.es>
|
||||
Jason Merino <jasonmerino@gmail.com>
|
||||
Jeremy Dunck <jdunck@gmail.com>
|
||||
Chris Price <price.c@gmail.com>
|
||||
Guy Bedford <guybedford@gmail.com>
|
||||
Amey Sakhadeo <me@ameyms.com>
|
||||
Mike Sidorov <mikes.ekb@gmail.com>
|
||||
Anthony Ryan <anthonyryan1@gmail.com>
|
||||
Dominik D. Geyer <dominik.geyer@gmail.com>
|
||||
George Kats <katsgeorgeek@gmail.com>
|
||||
Lihan Li <frankieteardrop@gmail.com>
|
||||
Ronny Springer <springer.ronny@gmail.com>
|
||||
Marian Sollmann <marian.sollmann@cargomedia.ch>
|
||||
Corey Frang <gnarf37@gmail.com>
|
||||
Chris Antaki <ChrisAntaki@gmail.com>
|
||||
Noah Hamann <njhamann@gmail.com>
|
||||
Marian Sollmann <marian.sollmann@cargomedia.ch>
|
||||
njhamann <njhamann@gmail.com>
|
||||
Ilya Kantor <iliakan@gmail.com>
|
||||
David Hong <d.hong@me.com>
|
||||
Jakob Stoeck <jakob@pokermania.de>
|
||||
Christopher Jones <christopherjonesqed@gmail.com>
|
||||
Forbes Lindesay <forbes@lindesay.co.uk>
|
||||
John Paul <john@johnkpaul.com>
|
||||
Jakob Stoeck <jakob@pokermania.de>
|
||||
Christopher Jones <chris@cjqed.com>
|
||||
Forbes Lindesay <forbes@lindesay.co.uk>
|
||||
S. Andrew Sheppard <andrew@wq.io>
|
||||
Leonardo Balter <leonardo.balter@gmail.com>
|
||||
Roman Reiß <me@silverwind.io>
|
||||
Benjy Cui <benjytrys@gmail.com>
|
||||
Rodrigo Rosenfeld Rosas <rr.rosas@gmail.com>
|
||||
John Hoven <hovenj@gmail.com>
|
||||
Philip Jägenstedt <philip@foolip.org>
|
||||
Christian Kosmowski <ksmwsk@gmail.com>
|
||||
Liang Peng <poppinlp@gmail.com>
|
||||
TJ VanToll <tj.vantoll@gmail.com>
|
||||
Senya Pugach <upisfree@outlook.com>
|
||||
Aurelio De Rosa <aurelioderosa@gmail.com>
|
||||
Nazar Mokrynskyi <nazar@mokrynskyi.com>
|
||||
Amit Merchant <bullredeyes@gmail.com>
|
||||
Jason Bedard <jason+github@jbedard.ca>
|
||||
Arthur Verschaeve <contact@arthurverschaeve.be>
|
||||
Dan Hart <danhart@notonthehighstreet.com>
|
||||
Scott González <scott.gonzalez@gmail.com>
|
||||
Zheming Sun <mescodasun@gmail.com>
|
||||
Bin Xin <rhyzix@gmail.com>
|
||||
David Corbacho <davidcorbacho@gmail.com>
|
||||
Veaceslav Grimalschi <grimalschi@yandex.ru>
|
||||
Daniel Husar <dano.husar@gmail.com>
|
||||
Jason Bedard <jason+github@jbedard.ca>
|
||||
Frederic Hemberger <mail@frederic-hemberger.de>
|
||||
Ben Toews <mastahyeti@gmail.com>
|
||||
Aditya Raghavan <araghavan3@gmail.com>
|
||||
Nicolas HENRY <icewil@gmail.com>
|
||||
Norman Xu <homyu.shinn@gmail.com>
|
||||
Anne-Gaelle Colom <coloma@westminster.ac.uk>
|
||||
Victor Homyakov <vkhomyackov@gmail.com>
|
||||
Shivaji Varma <contact@shivajivarma.com>
|
||||
Nicolas HENRY <icewil@gmail.com>
|
||||
Anne-Gaelle Colom <coloma@westminster.ac.uk>
|
||||
George Mauer <gmauer@gmail.com>
|
||||
Leonardo Braga <leonardo.braga@gmail.com>
|
||||
Stephen Edgar <stephen@netweb.com.au>
|
||||
@@ -246,21 +256,66 @@ Calvin Metcalf <calvin.metcalf@gmail.com>
|
||||
Mu Haibao <mhbseal@163.com>
|
||||
Richard McDaniel <rm0026@uah.edu>
|
||||
Chris Rebert <github@rebertia.com>
|
||||
Gabriel Schulhof <gabriel.schulhof@intel.com>
|
||||
Gilad Peleg <giladp007@gmail.com>
|
||||
Martin Naumann <martin@geekonaut.de>
|
||||
Marek Lewandowski <m.lewandowski@cksource.com>
|
||||
Bruno Pérel <brunoperel@gmail.com>
|
||||
Reed Loden <reed@reedloden.com>
|
||||
Daniel Nill <daniellnill@gmail.com>
|
||||
Yongwoo Jeon <yongwoo.jeon@navercorp.com>
|
||||
Sean Henderson <seanh.za@gmail.com>
|
||||
Adrian Olek <adrianolek@gmail.com>
|
||||
Richard Kraaijenhagen <stdin+git@riichard.com>
|
||||
Connor Atherton <c.liam.atherton@gmail.com>
|
||||
Gary Ye <garysye@gmail.com>
|
||||
Christian Grete <webmaster@christiangrete.com>
|
||||
Liza Ramo <liza.h.ramo@gmail.com>
|
||||
Joelle Fleurantin <joasqueeniebee@gmail.com>
|
||||
Julian Alexander Murillo <julian.alexander.murillo@gmail.com>
|
||||
Joelle Fleurantin <joasqueeniebee@gmail.com>
|
||||
Jae Sung Park <alberto.park@gmail.com>
|
||||
Jun Sun <klsforever@gmail.com>
|
||||
Josh Soref <apache@soref.com>
|
||||
Henry Wong <henryw4k@gmail.com>
|
||||
Jon Dufresne <jon.dufresne@gmail.com>
|
||||
Martijn W. van der Lee <martijn@vanderlee.com>
|
||||
Devin Wilson <dwilson6.github@gmail.com>
|
||||
Todor Prikumov <tono_pr@abv.bg>
|
||||
Steve Mao <maochenyan@gmail.com>
|
||||
Zack Hall <zackhall@outlook.com>
|
||||
Bernhard M. Wiedemann <jquerybmw@lsmod.de>
|
||||
Todor Prikumov <tono_pr@abv.bg>
|
||||
Jha Naman <createnaman@gmail.com>
|
||||
William Robinet <william.robinet@conostix.com>
|
||||
Alexander Lisianoi <all3fox@gmail.com>
|
||||
Vitaliy Terziev <vitaliyterziev@gmail.com>
|
||||
Joe Trumbull <trumbull.j@gmail.com>
|
||||
Alexander K <xpyro@ya.ru>
|
||||
Damian Senn <jquery@topaxi.codes>
|
||||
Ralin Chimev <ralin.chimev@gmail.com>
|
||||
Felipe Sateler <fsateler@gmail.com>
|
||||
Christophe Tafani-Dereeper <christophetd@hotmail.fr>
|
||||
Manoj Kumar <nithmanoj@gmail.com>
|
||||
David Broder-Rodgers <broder93@gmail.com>
|
||||
Alex Louden <alex@louden.com>
|
||||
Alex Padilla <alexonezero@outlook.com>
|
||||
南漂一卒 <shiy007@qq.com>
|
||||
karan-96 <karanbatra96@gmail.com>
|
||||
Boom Lee <teabyii@gmail.com>
|
||||
Andreas Solleder <asol@num42.de>
|
||||
CDAGaming <cstack2011@yahoo.com>
|
||||
Pierre Spring <pierre@nelm.io>
|
||||
Shashanka Nataraj <shashankan.10@gmail.com>
|
||||
Erik Lax <erik@datahack.se>
|
||||
Matan Kotler-Berkowitz <205matan@gmail.com>
|
||||
Jordan Beland <jordan.beland@gmail.com>
|
||||
Henry Zhu <hi@henryzoo.com>
|
||||
Saptak Sengupta <saptak013@gmail.com>
|
||||
Nilton Cesar <niltoncms@gmail.com>
|
||||
basil.belokon <basil.belokon@gmail.com>
|
||||
tmybr11 <tomas.perone@gmail.com>
|
||||
Luis Emilio Velasco Sanchez <emibloque@gmail.com>
|
||||
Ed S <ejsanders@gmail.com>
|
||||
Bert Zhang <enbo@users.noreply.github.com>
|
||||
Andrei Fangli <andrei_fangli@outlook.com>
|
||||
Marja Hölttä <marja.holtta@gmail.com>
|
||||
abnud1 <ahmad13932013@hotmail.com>
|
||||
buddh4 <mail@jharrer.de>
|
||||
|
||||
7736
inst/www/shared/jquery.js
vendored
7736
inst/www/shared/jquery.js
vendored
File diff suppressed because it is too large
Load Diff
7
inst/www/shared/jquery.min.js
vendored
7
inst/www/shared/jquery.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
@@ -117,7 +117,7 @@
|
||||
|
||||
// If this is the main Shiny window, wire up our custom message handler.
|
||||
if (window.Shiny) {
|
||||
Shiny.addCustomMessageHandler('reactlog', function(message) {
|
||||
Shiny.addCustomMessageHandler('showcase-src', function(message) {
|
||||
if (message.srcref && message.srcfile) {
|
||||
highlightSrcref(message.srcref, message.srcfile);
|
||||
}
|
||||
@@ -267,4 +267,3 @@
|
||||
if (window.hljs)
|
||||
hljs.initHighlightingOnLoad();
|
||||
})();
|
||||
|
||||
|
||||
@@ -1600,13 +1600,15 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
||||
function getTabIndex($tabset, tabsetId) {
|
||||
// The 0 is to ensure this works for empty tabsetPanels as well
|
||||
var existingTabIds = [0];
|
||||
var leadingHref = "#tab-" + tabsetId + "-";
|
||||
// loop through all existing tabs, find the one with highest id
|
||||
// (since this is based on a numeric counter), and increment
|
||||
$tabset.find("> li").each(function () {
|
||||
var $tab = $(this).find("> a[data-toggle='tab']");
|
||||
if ($tab.length > 0) {
|
||||
var index = $tab.attr("href").replace(leadingHref, "");
|
||||
// remove leading url if it exists. (copy of bootstrap url stripper)
|
||||
var href = $tab.attr("href").replace(/.*(?=#[^\s]+$)/, '');
|
||||
// remove tab id to get the index
|
||||
var index = href.replace("#tab-" + tabsetId + "-", "");
|
||||
existingTabIds.push(Number(index));
|
||||
}
|
||||
});
|
||||
@@ -4918,18 +4920,33 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
||||
if (date === undefined) return;
|
||||
if (date === null) {
|
||||
$(el).bsDatepicker('setStartDate', null);
|
||||
} else {
|
||||
date = this._newDate(date);
|
||||
date = this._UTCDateAsLocal(date);
|
||||
if (!isNaN(date)) {
|
||||
// Workaround for https://github.com/eternicode/bootstrap-datepicker/issues/2010
|
||||
// If the start date when there's a two-digit year format, it will set
|
||||
// the date value to null. So we'll save the value, set the start
|
||||
// date, and the restore the value.
|
||||
var curValue = $(el).bsDatepicker('getUTCDate');
|
||||
$(el).bsDatepicker('setStartDate', date);
|
||||
$(el).bsDatepicker('setUTCDate', curValue);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
date = this._newDate(date);
|
||||
// If date parsing fails, do nothing
|
||||
if (date === null) return;
|
||||
|
||||
date = this._UTCDateAsLocal(date);
|
||||
if (isNaN(date)) return;
|
||||
// Workaround for https://github.com/eternicode/bootstrap-datepicker/issues/2010
|
||||
// If the start date when there's a two-digit year format, it will set
|
||||
// the date value to null. So we'll save the value, set the start
|
||||
// date, and the restore the value.
|
||||
var curValue = $(el).bsDatepicker('getUTCDate');
|
||||
$(el).bsDatepicker('setStartDate', date);
|
||||
$(el).bsDatepicker('setUTCDate', curValue);
|
||||
|
||||
// Workaround for https://github.com/rstudio/shiny/issues/2335
|
||||
// We only set the start date *after* the value in this special
|
||||
// case so we don't effect the intended behavior of having a blank
|
||||
// value when it falls outside the start date
|
||||
if (typeof date.toDateString !== 'function') return;
|
||||
if (typeof curValue.toDateString !== 'function') return;
|
||||
if (date.toDateString() === curValue.toDateString()) {
|
||||
$(el).bsDatepicker('setStartDate', null);
|
||||
$(el).bsDatepicker('setUTCDate', curValue);
|
||||
$(el).bsDatepicker('setStartDate', date);
|
||||
}
|
||||
},
|
||||
// Given an unambiguous date string or a Date object, set the max (end) date
|
||||
@@ -4938,15 +4955,28 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
||||
if (date === undefined) return;
|
||||
if (date === null) {
|
||||
$(el).bsDatepicker('setEndDate', null);
|
||||
} else {
|
||||
date = this._newDate(date);
|
||||
date = this._UTCDateAsLocal(date);
|
||||
if (!isNaN(date)) {
|
||||
// Workaround for same issue as in _setMin.
|
||||
var curValue = $(el).bsDatepicker('getUTCDate');
|
||||
$(el).bsDatepicker('setEndDate', date);
|
||||
$(el).bsDatepicker('setUTCDate', curValue);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
date = this._newDate(date);
|
||||
// If date parsing fails, do nothing
|
||||
if (date === null) return;
|
||||
|
||||
date = this._UTCDateAsLocal(date);
|
||||
if (isNaN(date)) return;
|
||||
|
||||
// Workaround for same issue as in _setMin.
|
||||
var curValue = $(el).bsDatepicker('getUTCDate');
|
||||
$(el).bsDatepicker('setEndDate', date);
|
||||
$(el).bsDatepicker('setUTCDate', curValue);
|
||||
|
||||
// Workaround for same issue as in _setMin.
|
||||
if (typeof date.toDateString !== 'function') return;
|
||||
if (typeof curValue.toDateString !== 'function') return;
|
||||
if (date.toDateString() === curValue.toDateString()) {
|
||||
$(el).bsDatepicker('setEndDate', null);
|
||||
$(el).bsDatepicker('setUTCDate', curValue);
|
||||
$(el).bsDatepicker('setEndDate', date);
|
||||
}
|
||||
},
|
||||
// Given a date string of format yyyy-mm-dd, return a Date object with
|
||||
|
||||
File diff suppressed because one or more lines are too long
4
inst/www/shared/shiny.min.js
vendored
4
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
@@ -20,5 +20,5 @@ not to perform HTML escaping on it.
|
||||
\examples{
|
||||
el <- div(HTML("I like <u>turtles</u>"))
|
||||
cat(as.character(el))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/server.R
|
||||
\name{addResourcePath}
|
||||
\alias{addResourcePath}
|
||||
\title{Resource Publishing}
|
||||
\usage{
|
||||
addResourcePath(prefix, directoryPath)
|
||||
}
|
||||
\arguments{
|
||||
\item{prefix}{The URL prefix (without slashes). Valid characters are a-z,
|
||||
A-Z, 0-9, hyphen, period, and underscore.
|
||||
For example, a value of 'foo' means that any request paths that begin with
|
||||
'/foo' will be mapped to the given directory.}
|
||||
|
||||
\item{directoryPath}{The directory that contains the static resources to be
|
||||
served.}
|
||||
}
|
||||
\description{
|
||||
Adds a directory of static resources to Shiny's web server, with the given
|
||||
path prefix. Primarily intended for package authors to make supporting
|
||||
JavaScript/CSS files available to their components.
|
||||
}
|
||||
\examples{
|
||||
addResourcePath('datasets', system.file('data', package='datasets'))
|
||||
}
|
||||
\seealso{
|
||||
\code{\link[=singleton]{singleton()}}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/bootstrap.R
|
||||
% Please edit documentation in R/bootstrap-deprecated.R
|
||||
\name{bootstrapPage}
|
||||
\alias{bootstrapPage}
|
||||
\alias{basicPage}
|
||||
@@ -24,20 +24,9 @@ www directory, e.g. \code{www/bootstrap.css})}
|
||||
A UI defintion that can be passed to the \link{shinyUI} function.
|
||||
}
|
||||
\description{
|
||||
Create a Shiny UI page that loads the CSS and JavaScript for
|
||||
\href{http://getbootstrap.com/}{Bootstrap}, and has no content in the page
|
||||
body (other than what you provide).
|
||||
}
|
||||
\details{
|
||||
This function is primarily intended for users who are proficient in HTML/CSS,
|
||||
and know how to lay out pages in Bootstrap. Most applications should use
|
||||
\code{\link[=fluidPage]{fluidPage()}} along with layout functions like
|
||||
\code{\link[=fluidRow]{fluidRow()}} and \code{\link[=sidebarLayout]{sidebarLayout()}}.
|
||||
}
|
||||
\note{
|
||||
The \code{basicPage} function is deprecated, you should use the
|
||||
\code{\link[=fluidPage]{fluidPage()}} function instead.
|
||||
\strong{DEPRECATED}: use \code{\link[=fluidPage]{fluidPage()}} instead.
|
||||
}
|
||||
\seealso{
|
||||
\code{\link[=fluidPage]{fluidPage()}}, \code{\link[=fixedPage]{fixedPage()}}
|
||||
}
|
||||
\keyword{internal}
|
||||
|
||||
@@ -1,67 +1,73 @@
|
||||
\name{builder}
|
||||
\alias{a}
|
||||
\alias{br}
|
||||
\alias{builder}
|
||||
\alias{code}
|
||||
\alias{div}
|
||||
\alias{em}
|
||||
\alias{tags}
|
||||
\alias{p}
|
||||
\alias{h1}
|
||||
\alias{h2}
|
||||
\alias{h3}
|
||||
\alias{h4}
|
||||
\alias{h5}
|
||||
\alias{h6}
|
||||
\alias{hr}
|
||||
\alias{img}
|
||||
\alias{p}
|
||||
\alias{pre}
|
||||
\alias{a}
|
||||
\alias{br}
|
||||
\alias{div}
|
||||
\alias{span}
|
||||
\alias{pre}
|
||||
\alias{code}
|
||||
\alias{img}
|
||||
\alias{strong}
|
||||
\alias{tags}
|
||||
\alias{em}
|
||||
\alias{hr}
|
||||
\title{HTML Builder Functions}
|
||||
\usage{
|
||||
tags
|
||||
|
||||
p(...)
|
||||
p(..., .noWS = NULL)
|
||||
|
||||
h1(...)
|
||||
h1(..., .noWS = NULL)
|
||||
|
||||
h2(...)
|
||||
h2(..., .noWS = NULL)
|
||||
|
||||
h3(...)
|
||||
h3(..., .noWS = NULL)
|
||||
|
||||
h4(...)
|
||||
h4(..., .noWS = NULL)
|
||||
|
||||
h5(...)
|
||||
h5(..., .noWS = NULL)
|
||||
|
||||
h6(...)
|
||||
h6(..., .noWS = NULL)
|
||||
|
||||
a(...)
|
||||
a(..., .noWS = NULL)
|
||||
|
||||
br(...)
|
||||
br(..., .noWS = NULL)
|
||||
|
||||
div(...)
|
||||
div(..., .noWS = NULL)
|
||||
|
||||
span(...)
|
||||
span(..., .noWS = NULL)
|
||||
|
||||
pre(...)
|
||||
pre(..., .noWS = NULL)
|
||||
|
||||
code(...)
|
||||
code(..., .noWS = NULL)
|
||||
|
||||
img(...)
|
||||
img(..., .noWS = NULL)
|
||||
|
||||
strong(...)
|
||||
strong(..., .noWS = NULL)
|
||||
|
||||
em(...)
|
||||
em(..., .noWS = NULL)
|
||||
|
||||
hr(...)
|
||||
hr(..., .noWS = NULL)
|
||||
}
|
||||
\arguments{
|
||||
\item{...}{Attributes and children of the element. Named arguments become
|
||||
attributes, and positional arguments become children. Valid children are
|
||||
tags, single-character character vectors (which become text nodes), and raw
|
||||
HTML (see \code{\link{HTML}}). You can also pass lists that contain tags,
|
||||
text nodes, and HTML.}
|
||||
tags, single-character character vectors (which become text nodes), raw
|
||||
HTML (see \code{\link{HTML}}), and \code{html_dependency} objects. You can
|
||||
also pass lists that contain tags, text nodes, or HTML. To use boolean
|
||||
attributes, use a named argument with a \code{NA} value. (see example)}
|
||||
|
||||
\item{.noWS}{A character vector used to omit some of the whitespace that
|
||||
would normally be written around this tag. Valid options include
|
||||
\code{before}, \code{after}, \code{outside}, \code{after-begin}, and
|
||||
\code{before-end}. Any number of these options can be specified.}
|
||||
}
|
||||
\description{
|
||||
Simple functions for constructing HTML documents.
|
||||
@@ -75,7 +81,7 @@ Dedicated functions are available for the most common HTML tags that do not
|
||||
conflict with common R functions.
|
||||
|
||||
The result from these functions is a tag object, which can be converted using
|
||||
\code{\link[base]{as.character}()}.
|
||||
\code{\link{as.character}()}.
|
||||
}
|
||||
\examples{
|
||||
doc <- tags$html(
|
||||
@@ -92,5 +98,27 @@ doc <- tags$html(
|
||||
)
|
||||
)
|
||||
cat(as.character(doc))
|
||||
}
|
||||
|
||||
# create an html5 audio tag with controls.
|
||||
# controls is a boolean attributes
|
||||
audio_tag <- tags$audio(
|
||||
controls = NA,
|
||||
tags$source(
|
||||
src = "myfile.wav",
|
||||
type = "audio/wav"
|
||||
)
|
||||
)
|
||||
cat(as.character(audio_tag))
|
||||
|
||||
# suppress the whitespace between tags
|
||||
oneline <- tags$span(
|
||||
tags$strong("I'm strong", .noWS="outside")
|
||||
)
|
||||
cat(as.character(oneline))
|
||||
}
|
||||
\references{
|
||||
\itemize{
|
||||
\item W3C html specification about boolean attributes
|
||||
\url{https://www.w3.org/TR/html5/infrastructure.html#sec-boolean-attributes}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/bootstrap.R
|
||||
% Please edit documentation in R/bootstrap-deprecated.R
|
||||
\name{headerPanel}
|
||||
\alias{headerPanel}
|
||||
\title{Create a header panel}
|
||||
@@ -16,8 +16,6 @@ Useful if \code{title} is not a string.}
|
||||
A headerPanel that can be passed to \link{pageWithSidebar}
|
||||
}
|
||||
\description{
|
||||
Create a header panel containing an application title.
|
||||
}
|
||||
\examples{
|
||||
headerPanel("Hello Shiny!")
|
||||
\strong{DEPRECATED}: use \code{\link[=titlePanel]{titlePanel()}} instead.
|
||||
}
|
||||
\keyword{internal}
|
||||
|
||||
@@ -27,4 +27,3 @@ complete HTML document, then the returned object will also have class
|
||||
\seealso{
|
||||
\code{\link{renderDocument}}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
\name{include}
|
||||
\alias{include}
|
||||
\alias{includeCSS}
|
||||
\alias{includeHTML}
|
||||
\alias{includeMarkdown}
|
||||
\alias{includeScript}
|
||||
\alias{includeText}
|
||||
\alias{includeMarkdown}
|
||||
\alias{includeCSS}
|
||||
\alias{includeScript}
|
||||
\title{Include Content From a File}
|
||||
\usage{
|
||||
includeHTML(path)
|
||||
@@ -19,8 +19,8 @@ includeScript(path, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{path}{The path of the file to be included. It is highly recommended to
|
||||
use a relative path (the base path being the Shiny application directory),
|
||||
not an absolute path.}
|
||||
use a relative path (the base path being the Shiny application directory),
|
||||
not an absolute path.}
|
||||
|
||||
\item{...}{Any additional attributes to be applied to the generated tag.}
|
||||
}
|
||||
@@ -42,4 +42,3 @@ large literal R string.
|
||||
The \code{includeMarkdown} function requires the \code{markdown}
|
||||
package.
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
\name{knit_print.html}
|
||||
\alias{knit_print.html}
|
||||
\alias{knit_print.shiny.tag}
|
||||
\alias{knit_print.shiny.tag.list}
|
||||
\title{Knitr S3 methods}
|
||||
\usage{
|
||||
knit_print.shiny.tag(x, ...)
|
||||
|
||||
knit_print.html(x, ...)
|
||||
|
||||
knit_print.shiny.tag.list(x, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{x}{Object to knit_print}
|
||||
|
||||
\item{...}{Additional knit_print arguments}
|
||||
}
|
||||
\description{
|
||||
These S3 methods are necessary to allow HTML tags to print themselves in
|
||||
knitr/rmarkdown documents.
|
||||
}
|
||||
|
||||
31
man/loadSupport.Rd
Normal file
31
man/loadSupport.Rd
Normal file
@@ -0,0 +1,31 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/app.R
|
||||
\name{loadSupport}
|
||||
\alias{loadSupport}
|
||||
\title{Load an app's supporting R files}
|
||||
\usage{
|
||||
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
|
||||
be evaluated.}
|
||||
|
||||
\item{globalrenv}{The environment in which \code{global.R} should be evaluated. If
|
||||
\code{NULL}, \code{global.R} will not be evaluated at all.}
|
||||
}
|
||||
\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
|
||||
adjacent to the \code{app.R}/\code{server.R}/\code{ui.R} files.
|
||||
}
|
||||
\details{
|
||||
At the moment, this function is "opt-in" and only called if the option
|
||||
\code{shiny.autoload.r} is set to \code{TRUE}.
|
||||
|
||||
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.
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/bootstrap.R
|
||||
\name{mainPanel}
|
||||
\alias{mainPanel}
|
||||
\title{Create a main panel}
|
||||
\usage{
|
||||
mainPanel(..., width = 8)
|
||||
}
|
||||
\arguments{
|
||||
\item{...}{Output elements to include in the main panel}
|
||||
|
||||
\item{width}{The width of the main panel. For fluid layouts this is out of 12
|
||||
total units; for fixed layouts it is out of whatever the width of the main
|
||||
panel's parent column is.}
|
||||
}
|
||||
\value{
|
||||
A main panel that can be passed to \code{\link[=sidebarLayout]{sidebarLayout()}}.
|
||||
}
|
||||
\description{
|
||||
Create a main panel containing output elements that can in turn be passed to
|
||||
\code{\link[=sidebarLayout]{sidebarLayout()}}.
|
||||
}
|
||||
\examples{
|
||||
# Show the caption and plot of the requested variable against mpg
|
||||
mainPanel(
|
||||
h3(textOutput("caption")),
|
||||
plotOutput("mpgPlot")
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/bootstrap.R
|
||||
% Please edit documentation in R/bootstrap-deprecated.R
|
||||
\name{pageWithSidebar}
|
||||
\alias{pageWithSidebar}
|
||||
\title{Create a page with a sidebar}
|
||||
@@ -17,32 +17,6 @@ pageWithSidebar(headerPanel, sidebarPanel, mainPanel)
|
||||
A UI defintion that can be passed to the \link{shinyUI} function
|
||||
}
|
||||
\description{
|
||||
Create a Shiny UI that contains a header with the application title, a
|
||||
sidebar for input controls, and a main area for output.
|
||||
}
|
||||
\note{
|
||||
This function is deprecated. You should use \code{\link[=fluidPage]{fluidPage()}}
|
||||
along with \code{\link[=sidebarLayout]{sidebarLayout()}} to implement a page with a sidebar.
|
||||
}
|
||||
\examples{
|
||||
# Define UI
|
||||
pageWithSidebar(
|
||||
|
||||
# Application title
|
||||
headerPanel("Hello Shiny!"),
|
||||
|
||||
# Sidebar with a slider input
|
||||
sidebarPanel(
|
||||
sliderInput("obs",
|
||||
"Number of observations:",
|
||||
min = 0,
|
||||
max = 1000,
|
||||
value = 500)
|
||||
),
|
||||
|
||||
# Show a plot of the generated distribution
|
||||
mainPanel(
|
||||
plotOutput("distPlot")
|
||||
)
|
||||
)
|
||||
\strong{DEPRECATED}: use \code{\link[=fluidPage]{fluidPage()}} and \code{\link[=sidebarLayout]{sidebarLayout()}} instead.
|
||||
}
|
||||
\keyword{internal}
|
||||
|
||||
@@ -45,7 +45,7 @@ invalidated, any other reactive expressions that recently called it are also
|
||||
marked as invalidated. In this way, invalidations ripple through the
|
||||
expressions that depend on each other.
|
||||
|
||||
See the \href{http://rstudio.github.com/shiny/tutorial/}{Shiny tutorial} for
|
||||
See the \href{https://shiny.rstudio.com/tutorial/}{Shiny tutorial} for
|
||||
more information about reactive expressions.
|
||||
}
|
||||
\examples{
|
||||
|
||||
@@ -7,16 +7,16 @@
|
||||
reactiveValuesToList(x, all.names = FALSE)
|
||||
}
|
||||
\arguments{
|
||||
\item{x}{A reactivevalues object.}
|
||||
\item{x}{A \code{reactivevalues} object.}
|
||||
|
||||
\item{all.names}{If \code{TRUE}, include objects with a leading dot. If
|
||||
\code{FALSE} (the default) don't include those objects.}
|
||||
\item{all.names}{If \code{TRUE}, include objects with a leading dot. If \code{FALSE}
|
||||
(the default) don't include those objects.}
|
||||
}
|
||||
\description{
|
||||
This function does something similar to what you might \code{\link[base:as.list]{base::as.list()}}
|
||||
to do. The difference is that the calling context will take dependencies on
|
||||
every object in the reactivevalues object. To avoid taking dependencies on
|
||||
all the objects, you can wrap the call with \code{\link[=isolate]{isolate()}}.
|
||||
This function does something similar to what you might want or expect
|
||||
\code{\link[base:as.list]{base::as.list()}} to do. The difference is that the calling context will take
|
||||
dependencies on every object in the \code{reactivevalue}s object. To avoid taking
|
||||
dependencies on all the objects, you can wrap the call with \code{\link[=isolate]{isolate()}}.
|
||||
}
|
||||
\examples{
|
||||
values <- reactiveValues(a = 1)
|
||||
|
||||
@@ -11,13 +11,19 @@ renderPlot(expr, width = "auto", height = "auto", res = 72, ...,
|
||||
\arguments{
|
||||
\item{expr}{An expression that generates a plot.}
|
||||
|
||||
\item{width, height}{The width/height of the rendered plot, in pixels; or
|
||||
\code{'auto'} to use the \code{offsetWidth}/\code{offsetHeight} of the HTML
|
||||
element that is bound to this plot. You can also pass in a function that
|
||||
returns the width/height in pixels or \code{'auto'}; in the body of the
|
||||
function you may reference reactive values and functions. When rendering an
|
||||
inline plot, you must provide numeric values (in pixels) to both
|
||||
\code{width} and \code{height}.}
|
||||
\item{width, height}{Height and width can be specified in three ways:
|
||||
\itemize{
|
||||
\item \code{"auto"}, the default, uses the size specified by \code{\link[=plotOutput]{plotOutput()}}
|
||||
(i.e. the \code{offsetWidth}/`offsetHeight`` of the HTML element bound to
|
||||
this plot.)
|
||||
\item An integer, defining the width/height in pixels.
|
||||
\item A function that returns the width/height in pixels (or \code{"auto"}).
|
||||
The function is executed in a reactive context so that you can refer to
|
||||
reactive values and expression to make the width/height reactive.
|
||||
}
|
||||
|
||||
When rendering an inline plot, you must provide numeric values (in pixels)
|
||||
to both \code{width} and \code{height}.}
|
||||
|
||||
\item{res}{Resolution of resulting plot, in pixels per inch. This value is
|
||||
passed to \code{\link[grDevices:png]{grDevices::png()}}. Note that this affects the resolution of PNG
|
||||
|
||||
59
man/resourcePaths.Rd
Normal file
59
man/resourcePaths.Rd
Normal file
@@ -0,0 +1,59 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/server.R
|
||||
\name{addResourcePath}
|
||||
\alias{addResourcePath}
|
||||
\alias{resourcePaths}
|
||||
\alias{removeResourcePath}
|
||||
\title{Resource Publishing}
|
||||
\usage{
|
||||
addResourcePath(prefix, directoryPath)
|
||||
|
||||
resourcePaths()
|
||||
|
||||
removeResourcePath(prefix)
|
||||
}
|
||||
\arguments{
|
||||
\item{prefix}{The URL prefix (without slashes). Valid characters are a-z,
|
||||
A-Z, 0-9, hyphen, period, and underscore. For example, a value of 'foo'
|
||||
means that any request paths that begin with '/foo' will be mapped to the
|
||||
given directory.}
|
||||
|
||||
\item{directoryPath}{The directory that contains the static resources to be
|
||||
served.}
|
||||
}
|
||||
\description{
|
||||
Add, remove, or list directory of static resources to Shiny's web server,
|
||||
with the given path prefix. Primarily intended for package authors to make
|
||||
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
|
||||
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}.
|
||||
}
|
||||
|
||||
The second approach is primarily intended for package authors to make
|
||||
supporting JavaScript/CSS files available to their components.
|
||||
|
||||
Tools for managing static resources published by Shiny's web server:
|
||||
\itemize{
|
||||
\item \code{addResourcePath()} adds a directory of static resources.
|
||||
\item \code{resourcePaths()} lists the currently active resource mappings.
|
||||
\item \code{removeResourcePath()} removes a directory of static resources.
|
||||
}
|
||||
}
|
||||
\examples{
|
||||
addResourcePath('datasets', system.file('data', package='datasets'))
|
||||
resourcePaths()
|
||||
removeResourcePath('datasets')
|
||||
resourcePaths()
|
||||
|
||||
# make sure all resources are removed
|
||||
lapply(names(resourcePaths()), removeResourcePath)
|
||||
}
|
||||
\seealso{
|
||||
\code{\link[=singleton]{singleton()}}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/shiny.R
|
||||
\name{shiny-options}
|
||||
\alias{shiny-options}
|
||||
\title{Global options for Shiny}
|
||||
\description{
|
||||
There are a number of global options that affect Shiny's behavior. These can
|
||||
be set with (for example) \code{options(shiny.trace=TRUE)}.
|
||||
}
|
||||
\details{
|
||||
\describe{
|
||||
\item{shiny.launch.browser}{A boolean which controls the default behavior
|
||||
when an app is run. See \code{\link[=runApp]{runApp()}} for more information.}
|
||||
\item{shiny.port}{A port number that Shiny will listen on. See
|
||||
\code{\link[=runApp]{runApp()}} for more information.}
|
||||
\item{shiny.trace}{Print messages sent between the R server and the web
|
||||
browser client to the R console. This is useful for debugging. Possible
|
||||
values are \code{"send"} (only print messages sent to the client),
|
||||
\code{"recv"} (only print messages received by the server), \code{TRUE}
|
||||
(print all messages), or \code{FALSE} (default; don't print any of these
|
||||
messages).}
|
||||
\item{shiny.autoreload}{If \code{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.
|
||||
|
||||
You can customize the file patterns Shiny will monitor by setting the
|
||||
shiny.autoreload.pattern option. For example, to monitor only ui.R:
|
||||
\code{options(shiny.autoreload.pattern = glob2rx("ui.R"))}
|
||||
|
||||
The default polling interval is 500 milliseconds. You can change this
|
||||
by setting e.g. \code{options(shiny.autoreload.interval = 2000)} (every
|
||||
two seconds).}
|
||||
\item{shiny.reactlog}{If \code{TRUE}, enable logging of reactive events,
|
||||
which can be viewed later with the \code{\link[=reactlogShow]{reactlogShow()}} function.
|
||||
This incurs a substantial performance penalty and should not be used in
|
||||
production.}
|
||||
\item{shiny.usecairo}{This is used to disable graphical rendering by the
|
||||
Cairo package, if it is installed. See \code{\link[=plotPNG]{plotPNG()}} for more
|
||||
information.}
|
||||
\item{shiny.maxRequestSize}{This is a number which specifies the maximum
|
||||
web request size, which serves as a size limit for file uploads. If
|
||||
unset, the maximum request size defaults to 5MB.}
|
||||
\item{shiny.suppressMissingContextError}{Normally, invoking a reactive
|
||||
outside of a reactive context (or \code{\link[=isolate]{isolate()}}) results in
|
||||
an error. If this is \code{TRUE}, don't error in these cases. This
|
||||
should only be used for debugging or demonstrations of reactivity at the
|
||||
console.}
|
||||
\item{shiny.host}{The IP address that Shiny should listen on. See
|
||||
\code{\link[=runApp]{runApp()}} for more information.}
|
||||
\item{shiny.json.digits}{The number of digits to use when converting
|
||||
numbers to JSON format to send to the client web browser.}
|
||||
\item{shiny.minified}{If this is \code{TRUE} or unset (the default), then
|
||||
Shiny will use minified JavaScript (\code{shiny.min.js}). If
|
||||
\code{FALSE}, then Shiny will use the un-minified JavaScript
|
||||
(\code{shiny.js}); this can be useful during development.}
|
||||
\item{shiny.error}{This can be a function which is called when an error
|
||||
occurs. For example, \code{options(shiny.error=recover)} will result a
|
||||
the debugger prompt when an error occurs.}
|
||||
\item{shiny.table.class}{CSS class names to use for tables.}
|
||||
\item{shiny.deprecation.messages}{This controls whether messages for
|
||||
deprecated functions in Shiny will be printed. See
|
||||
\code{\link[=shinyDeprecated]{shinyDeprecated()}} for more information.}
|
||||
\item{shiny.fullstacktrace}{Controls whether "pretty" or full stack traces
|
||||
are dumped to the console when errors occur during Shiny app execution.
|
||||
The default is \code{FALSE} (pretty stack traces).}
|
||||
\item{shiny.stacktraceoffset}{If \code{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.sanitize.errors}{If \code{TRUE}, then normal errors (i.e.
|
||||
errors not wrapped in \code{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). The default is \code{FALSE} (unsanitized
|
||||
errors).If you want to sanitize errors in general, but you DO want a
|
||||
particular error \code{e} to get displayed to the user, then set this option
|
||||
to \code{TRUE} and use \code{stop(safeError(e))} for errors you want the
|
||||
user to see.}
|
||||
\item{shiny.testmode}{If \code{TRUE}, then enable features for testing Shiny
|
||||
applications. If \code{FALSE} (the default), do not enable those features.
|
||||
}
|
||||
}
|
||||
}
|
||||
36
man/shiny.appobj.Rd
Normal file
36
man/shiny.appobj.Rd
Normal file
@@ -0,0 +1,36 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/app.R
|
||||
\name{shiny.appobj}
|
||||
\alias{shiny.appobj}
|
||||
\alias{as.shiny.appobj}
|
||||
\alias{as.shiny.appobj.shiny.appobj}
|
||||
\alias{as.shiny.appobj.list}
|
||||
\alias{as.shiny.appobj.character}
|
||||
\alias{is.shiny.appobj}
|
||||
\alias{print.shiny.appobj}
|
||||
\alias{as.tags.shiny.appobj}
|
||||
\title{Shiny App object}
|
||||
\usage{
|
||||
as.shiny.appobj(x)
|
||||
|
||||
\method{as.shiny.appobj}{shiny.appobj}(x)
|
||||
|
||||
\method{as.shiny.appobj}{list}(x)
|
||||
|
||||
\method{as.shiny.appobj}{character}(x)
|
||||
|
||||
is.shiny.appobj(x)
|
||||
|
||||
\method{print}{shiny.appobj}(x, ...)
|
||||
|
||||
\method{as.tags}{shiny.appobj}(x, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{x}{Object to convert to a Shiny app.}
|
||||
|
||||
\item{...}{Additional parameters to be passed to print.}
|
||||
}
|
||||
\description{
|
||||
Internal methods for the \code{shiny.appobj} S3 class.
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -4,41 +4,22 @@
|
||||
\alias{shinyApp}
|
||||
\alias{shinyAppDir}
|
||||
\alias{shinyAppFile}
|
||||
\alias{as.shiny.appobj}
|
||||
\alias{as.shiny.appobj.shiny.appobj}
|
||||
\alias{as.shiny.appobj.list}
|
||||
\alias{as.shiny.appobj.character}
|
||||
\alias{is.shiny.appobj}
|
||||
\alias{print.shiny.appobj}
|
||||
\alias{as.tags.shiny.appobj}
|
||||
\title{Create a Shiny app object}
|
||||
\usage{
|
||||
shinyApp(ui = NULL, server = NULL, onStart = NULL,
|
||||
options = list(), uiPattern = "/", enableBookmarking = NULL)
|
||||
shinyApp(ui, server, onStart = NULL, options = list(),
|
||||
uiPattern = "/", enableBookmarking = NULL)
|
||||
|
||||
shinyAppDir(appDir, options = list())
|
||||
|
||||
shinyAppFile(appFile, options = list())
|
||||
|
||||
as.shiny.appobj(x)
|
||||
|
||||
\method{as.shiny.appobj}{shiny.appobj}(x)
|
||||
|
||||
\method{as.shiny.appobj}{list}(x)
|
||||
|
||||
\method{as.shiny.appobj}{character}(x)
|
||||
|
||||
is.shiny.appobj(x)
|
||||
|
||||
\method{print}{shiny.appobj}(x, ...)
|
||||
|
||||
\method{as.tags}{shiny.appobj}(x, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{ui}{The UI definition of the app (for example, a call to
|
||||
\code{fluidPage()} with nested controls)}
|
||||
|
||||
\item{server}{A server function}
|
||||
\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
|
||||
app is independent.}
|
||||
|
||||
\item{onStart}{A function that will be called before the app is actually run.
|
||||
This is only needed for \code{shinyAppObj}, since in the \code{shinyAppDir}
|
||||
@@ -66,10 +47,6 @@ See \code{\link[=enableBookmarking]{enableBookmarking()}} for more information.}
|
||||
file and either ui.R or www/index.html)}
|
||||
|
||||
\item{appFile}{Path to a .R file containing a Shiny application}
|
||||
|
||||
\item{x}{Object to convert to a Shiny app.}
|
||||
|
||||
\item{...}{Additional parameters to be passed to print.}
|
||||
}
|
||||
\value{
|
||||
An object that represents the app. Printing the object or passing it
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
\name{getShinyOption}
|
||||
\alias{getShinyOption}
|
||||
\alias{shinyOptions}
|
||||
\alias{shiny-options}
|
||||
\title{Get or set Shiny options}
|
||||
\usage{
|
||||
getShinyOption(name, default = NULL)
|
||||
@@ -17,19 +18,105 @@ shinyOptions(...)
|
||||
\item{...}{Options to set, with the form \code{name = value}.}
|
||||
}
|
||||
\description{
|
||||
\code{getShinyOption} retrieves the value of a Shiny option.
|
||||
\code{shinyOptions} sets the value of Shiny options; it can also be used to
|
||||
return a list of all currently-set Shiny options.
|
||||
\code{getShinyOption()} retrieves the value of a Shiny option. \code{shinyOptions()}
|
||||
sets the value of Shiny options; it can also be used to return a list of all
|
||||
currently-set Shiny options.
|
||||
}
|
||||
\details{
|
||||
There is a global option set, which is available by default. When a Shiny
|
||||
application is run with \code{\link[=runApp]{runApp()}}, that option set is duplicated
|
||||
and the new option set is available for getting or setting values. If options
|
||||
are set from global.R, app.R, ui.R, or server.R, or if they are set from
|
||||
inside the server function, then the options will be scoped to the
|
||||
\section{Scope}{
|
||||
|
||||
There is a global option set which is available by default. When a Shiny
|
||||
application is run with \code{\link[=runApp]{runApp()}}, that option set is duplicated and the
|
||||
new option set is available for getting or setting values. If options
|
||||
are set from \code{global.R}, \code{app.R}, \code{ui.R}, or \code{server.R}, or if they are set
|
||||
from inside the server function, then the options will be scoped to the
|
||||
application. When the application exits, the new option set is discarded and
|
||||
the global option set is restored.
|
||||
}
|
||||
|
||||
\section{Options}{
|
||||
|
||||
There are a number of global options that affect Shiny's behavior. These can
|
||||
be set globally with \code{options()} or locally (for a single app) with
|
||||
\code{shinyOptions()}.
|
||||
|
||||
\describe{
|
||||
\item{shiny.autoreload}{If \code{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.\preformatted{Since monitoring for changes is expensive (we simply poll for last
|
||||
modified times), this feature is intended only for development.
|
||||
|
||||
You can customize the file patterns Shiny will monitor by setting the
|
||||
shiny.autoreload.pattern option. For example, to monitor only ui.R:
|
||||
`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}{This controls whether messages for
|
||||
deprecated functions in Shiny will be printed. See
|
||||
\code{\link[=shinyDeprecated]{shinyDeprecated()}} for more information.}
|
||||
\item{shiny.error}{This can be a function which is called when an error
|
||||
occurs. For example, \code{options(shiny.error=recover)} will result a
|
||||
the debugger prompt when an error occurs.}
|
||||
\item{shiny.fullstacktrace}{Controls whether "pretty" or full stack traces
|
||||
are dumped to the console when errors occur during Shiny app execution.
|
||||
The default is \code{FALSE} (pretty stack traces).}
|
||||
\item{shiny.host}{The IP address that Shiny should listen on. See
|
||||
\code{\link[=runApp]{runApp()}} for more information.}
|
||||
\item{shiny.json.digits}{The number of digits to use when converting
|
||||
numbers to JSON format to send to the client web browser.}
|
||||
\item{shiny.launch.browser}{A boolean which controls the default behavior
|
||||
when an app is run. See \code{\link[=runApp]{runApp()}} for more information.}
|
||||
\item{shiny.maxRequestSize}{This is a number which specifies the maximum
|
||||
web request size, which serves as a size limit for file uploads. If
|
||||
unset, the maximum request size defaults to 5MB.}
|
||||
\item{shiny.minified}{If this is \code{TRUE} or unset (the default), then
|
||||
Shiny will use minified JavaScript (\code{shiny.min.js}). If
|
||||
\code{FALSE}, then Shiny will use the un-minified JavaScript
|
||||
(\code{shiny.js}); this can be useful during development.}
|
||||
\item{shiny.port}{A port number that Shiny will listen on. See
|
||||
\code{\link[=runApp]{runApp()}} for more information.}
|
||||
\item{shiny.reactlog}{If \code{TRUE}, enable logging of reactive events,
|
||||
which can be viewed later with the \code{\link[=reactlogShow]{reactlogShow()}} function.
|
||||
This incurs a substantial performance penalty and should not be used in
|
||||
production.}
|
||||
\item{shiny.sanitize.errors}{If \code{TRUE}, then normal errors (i.e.
|
||||
errors not wrapped in \code{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). The default is \code{FALSE} (unsanitized
|
||||
errors).If you want to sanitize errors in general, but you DO want a
|
||||
particular error \code{e} to get displayed to the user, then set this option
|
||||
to \code{TRUE} and use \code{stop(safeError(e))} for errors you want the
|
||||
user to see.}
|
||||
\item{shiny.stacktraceoffset}{If \code{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}{Normally, invoking a reactive
|
||||
outside of a reactive context (or \code{\link[=isolate]{isolate()}}) results in
|
||||
an error. If this is \code{TRUE}, don't error in these cases. This
|
||||
should only be used for debugging or demonstrations of reactivity at the
|
||||
console.}
|
||||
\item{shiny.table.class}{CSS class names to use for tables.}
|
||||
\item{shiny.testmode}{If \code{TRUE}, then enable features for testing Shiny
|
||||
applications. If \code{FALSE} (the default), do not enable those features.}
|
||||
\item{shiny.trace}{Print messages sent between the R server and the web
|
||||
browser client to the R console. This is useful for debugging. Possible
|
||||
values are \code{"send"} (only print messages sent to the client),
|
||||
\code{"recv"} (only print messages received by the server), \code{TRUE}
|
||||
(print all messages), or \code{FALSE} (default; don't print any of these
|
||||
messages).}
|
||||
\item{shiny.usecairo}{This is used to disable graphical rendering by the
|
||||
Cairo package, if it is installed. See \code{\link[=plotPNG]{plotPNG()}} for more
|
||||
information.}
|
||||
}
|
||||
}
|
||||
|
||||
\examples{
|
||||
\dontrun{
|
||||
shinyOptions(myOption = 10)
|
||||
|
||||
@@ -2,25 +2,38 @@
|
||||
% Please edit documentation in R/bootstrap-layout.R
|
||||
\name{sidebarLayout}
|
||||
\alias{sidebarLayout}
|
||||
\alias{sidebarPanel}
|
||||
\alias{mainPanel}
|
||||
\title{Layout a sidebar and main area}
|
||||
\usage{
|
||||
sidebarLayout(sidebarPanel, mainPanel, position = c("left", "right"),
|
||||
fluid = TRUE)
|
||||
|
||||
sidebarPanel(..., width = 4)
|
||||
|
||||
mainPanel(..., width = 8)
|
||||
}
|
||||
\arguments{
|
||||
\item{sidebarPanel}{The \link{sidebarPanel} containing input controls}
|
||||
\item{sidebarPanel}{The \code{sidebarPanel()} containing input controls.}
|
||||
|
||||
\item{mainPanel}{The \link{mainPanel} containing outputs}
|
||||
\item{mainPanel}{The \code{mainPanel()} containing outputs.}
|
||||
|
||||
\item{position}{The position of the sidebar relative to the main area ("left"
|
||||
or "right")}
|
||||
or "right").}
|
||||
|
||||
\item{fluid}{\code{TRUE} to use fluid layout; \code{FALSE} to use fixed
|
||||
layout.}
|
||||
|
||||
\item{...}{Output elements to include in the sidebar/main panel.}
|
||||
|
||||
\item{width}{The width of the sidebar and main panel. By default, the
|
||||
sidebar takes up 1/3 of the width, and the main panel 2/3. The total
|
||||
width must be 12 or less.}
|
||||
}
|
||||
\description{
|
||||
Create a layout with a sidebar and main area. The sidebar is displayed with a
|
||||
distinct background color and typically contains input controls. The main
|
||||
Create a layout (\code{sidebarLayout()}) with a sidebar (\code{sidebarPanel()}) and
|
||||
main area (\code{mainPanel()}). The sidebar is displayed with a distinct
|
||||
background color and typically contains input controls. The main
|
||||
area occupies 2/3 of the horizontal width and typically contains outputs.
|
||||
}
|
||||
\examples{
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/bootstrap.R
|
||||
\name{sidebarPanel}
|
||||
\alias{sidebarPanel}
|
||||
\title{Create a sidebar panel}
|
||||
\usage{
|
||||
sidebarPanel(..., width = 4)
|
||||
}
|
||||
\arguments{
|
||||
\item{...}{UI elements to include on the sidebar}
|
||||
|
||||
\item{width}{The width of the sidebar. For fluid layouts this is out of 12
|
||||
total units; for fixed layouts it is out of whatever the width of the
|
||||
sidebar's parent column is.}
|
||||
}
|
||||
\value{
|
||||
A sidebar that can be passed to \code{\link[=sidebarLayout]{sidebarLayout()}}
|
||||
}
|
||||
\description{
|
||||
Create a sidebar panel containing input controls that can in turn be passed
|
||||
to \code{\link[=sidebarLayout]{sidebarLayout()}}.
|
||||
}
|
||||
\examples{
|
||||
# Sidebar with controls to select a dataset and specify
|
||||
# the number of observations to view
|
||||
sidebarPanel(
|
||||
selectInput("dataset", "Choose a dataset:",
|
||||
choices = c("rock", "pressure", "cars")),
|
||||
|
||||
numericInput("obs", "Observations:", 10)
|
||||
)
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
\name{singleton}
|
||||
\alias{is.singleton}
|
||||
\alias{singleton}
|
||||
\alias{is.singleton}
|
||||
\title{Include content only once}
|
||||
\usage{
|
||||
singleton(x, value = TRUE)
|
||||
@@ -18,4 +18,3 @@ be included in the generated document only once, yet may appear in the
|
||||
document-generating code more than once. Only the first appearance of the
|
||||
content (in document order) will be used.
|
||||
}
|
||||
|
||||
|
||||
@@ -19,4 +19,3 @@ HTML template.
|
||||
|
||||
\code{\link[htmltools]{htmlDependency}}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,8 @@ valid when using a \code{tabPanel} within a \code{\link[=navbarPage]{navbarPage(
|
||||
A tab that can be passed to \code{\link[=tabsetPanel]{tabsetPanel()}}
|
||||
}
|
||||
\description{
|
||||
Create a tab panel that can be included within a \code{\link[=tabsetPanel]{tabsetPanel()}}.
|
||||
Create a tab panel that can be included within a \code{\link[=tabsetPanel]{tabsetPanel()}} or
|
||||
a \code{\link[=navbarPage]{navbarPage()}}.
|
||||
}
|
||||
\examples{
|
||||
# Show a tabset that includes a plot, summary, and
|
||||
|
||||
42
man/tag.Rd
42
man/tag.Rd
@@ -1,9 +1,11 @@
|
||||
\name{tag}
|
||||
\alias{tag}
|
||||
\alias{tagList}
|
||||
\alias{tagAppendAttributes}
|
||||
\alias{tagHasAttribute}
|
||||
\alias{tagGetAttribute}
|
||||
\alias{tagAppendChild}
|
||||
\alias{tagAppendChildren}
|
||||
\alias{tagList}
|
||||
\alias{tagSetChildren}
|
||||
\title{HTML Tag Object}
|
||||
\usage{
|
||||
@@ -11,15 +13,30 @@ tagList(...)
|
||||
|
||||
tagAppendAttributes(tag, ...)
|
||||
|
||||
tagHasAttribute(tag, attr)
|
||||
|
||||
tagGetAttribute(tag, attr)
|
||||
|
||||
tagAppendChild(tag, child)
|
||||
|
||||
tagAppendChildren(tag, ..., list = NULL)
|
||||
|
||||
tagSetChildren(tag, ..., list = NULL)
|
||||
|
||||
tag(`_tag_name`, varArgs)
|
||||
tag(`_tag_name`, varArgs, .noWS = NULL)
|
||||
}
|
||||
\arguments{
|
||||
\item{...}{Unnamed items that comprise this list of tags.}
|
||||
|
||||
\item{tag}{A tag to append child elements to.}
|
||||
|
||||
\item{attr}{The name of an attribute.}
|
||||
|
||||
\item{child}{A child element to append to a parent tag.}
|
||||
|
||||
\item{list}{An optional list of elements. Can be used with or instead of the
|
||||
\code{...} items.}
|
||||
|
||||
\item{_tag_name}{HTML tag name}
|
||||
|
||||
\item{varArgs}{List of attributes and children of the element. Named list
|
||||
@@ -28,18 +45,14 @@ children are tags, single-character character vectors (which become text
|
||||
nodes), and raw HTML (see \code{\link{HTML}}). You can also pass lists that
|
||||
contain tags, text nodes, and HTML.}
|
||||
|
||||
\item{tag}{A tag to append child elements to.}
|
||||
|
||||
\item{child}{A child element to append to a parent tag.}
|
||||
|
||||
\item{...}{Unnamed items that comprise this list of tags.}
|
||||
|
||||
\item{list}{An optional list of elements. Can be used with or instead of the
|
||||
\code{...} items.}
|
||||
\item{.noWS}{Character vector used to omit some of the whitespace that would
|
||||
normally be written around this tag. Valid options include \code{before},
|
||||
\code{after}, \code{outside}, \code{after-begin}, and \code{before-end}.
|
||||
Any number of these options can be specified.}
|
||||
}
|
||||
\value{
|
||||
An HTML tag object that can be rendered as HTML using
|
||||
\code{\link[base]{as.character}()}.
|
||||
\code{\link{as.character}()}.
|
||||
}
|
||||
\description{
|
||||
\code{tag()} creates an HTML tag definition. Note that all of the valid HTML5
|
||||
@@ -60,5 +73,10 @@ x <- list(tags$h1("Title"),
|
||||
tags$h2("Header text"),
|
||||
tags$p("Text here"))
|
||||
tagList(x)
|
||||
}
|
||||
|
||||
# suppress the whitespace between tags
|
||||
oneline <- tag("span",
|
||||
tag("strong", "Super strong", .noWS="outside")
|
||||
)
|
||||
cat(as.character(oneline))
|
||||
}
|
||||
|
||||
@@ -22,10 +22,12 @@ Single element numeric vectors are returned as a character vector with the
|
||||
number plus a suffix of \code{"px"}.
|
||||
|
||||
Single element character vectors must be \code{"auto"} or \code{"inherit"},
|
||||
or a number. If the number has a suffix, it must be valid: \code{px},
|
||||
\code{\%}, \code{em}, \code{pt}, \code{in}, \code{cm}, \code{mm}, \code{ex},
|
||||
or \code{pc}. If the number has no suffix, the suffix \code{"px"} is
|
||||
appended.
|
||||
a number, or a length calculated by the \code{"calc"} CSS function.
|
||||
If the number has a suffix, it must be valid: \code{px},
|
||||
\code{\%}, \code{ch}, \code{em}, \code{rem}, \code{pt}, \code{in}, \code{cm},
|
||||
\code{mm}, \code{ex}, \code{pc}, \code{vh}, \code{vw}, \code{vmin}, or
|
||||
\code{vmax}.
|
||||
If the number has no suffix, the suffix \code{"px"} is appended.
|
||||
|
||||
Any other value will cause an error to be thrown.
|
||||
}
|
||||
@@ -33,4 +35,3 @@ Any other value will cause an error to be thrown.
|
||||
validateCssUnit("10\%")
|
||||
validateCssUnit(400) #treated as '400px'
|
||||
}
|
||||
|
||||
|
||||
@@ -34,5 +34,6 @@ withTags(
|
||||
p("text")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -139,19 +139,35 @@ $.extend(dateInputBinding, {
|
||||
return;
|
||||
if (date === null) {
|
||||
$(el).bsDatepicker('setStartDate', null);
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
date = this._newDate(date);
|
||||
date = this._UTCDateAsLocal(date);
|
||||
if (!isNaN(date)) {
|
||||
// Workaround for https://github.com/eternicode/bootstrap-datepicker/issues/2010
|
||||
// If the start date when there's a two-digit year format, it will set
|
||||
// the date value to null. So we'll save the value, set the start
|
||||
// date, and the restore the value.
|
||||
var curValue = $(el).bsDatepicker('getUTCDate');
|
||||
$(el).bsDatepicker('setStartDate', date);
|
||||
$(el).bsDatepicker('setUTCDate', curValue);
|
||||
}
|
||||
date = this._newDate(date);
|
||||
// If date parsing fails, do nothing
|
||||
if (date === null)
|
||||
return;
|
||||
|
||||
date = this._UTCDateAsLocal(date);
|
||||
if (isNaN(date))
|
||||
return;
|
||||
// Workaround for https://github.com/eternicode/bootstrap-datepicker/issues/2010
|
||||
// If the start date when there's a two-digit year format, it will set
|
||||
// the date value to null. So we'll save the value, set the start
|
||||
// date, and the restore the value.
|
||||
var curValue = $(el).bsDatepicker('getUTCDate');
|
||||
$(el).bsDatepicker('setStartDate', date);
|
||||
$(el).bsDatepicker('setUTCDate', curValue);
|
||||
|
||||
// Workaround for https://github.com/rstudio/shiny/issues/2335
|
||||
// We only set the start date *after* the value in this special
|
||||
// case so we don't effect the intended behavior of having a blank
|
||||
// value when it falls outside the start date
|
||||
if (typeof date.toDateString !== 'function') return;
|
||||
if (typeof curValue.toDateString !== 'function') return;
|
||||
if (date.toDateString() === curValue.toDateString()) {
|
||||
$(el).bsDatepicker('setStartDate', null);
|
||||
$(el).bsDatepicker('setUTCDate', curValue);
|
||||
$(el).bsDatepicker('setStartDate', date);
|
||||
}
|
||||
},
|
||||
// Given an unambiguous date string or a Date object, set the max (end) date
|
||||
@@ -161,16 +177,30 @@ $.extend(dateInputBinding, {
|
||||
return;
|
||||
if (date === null) {
|
||||
$(el).bsDatepicker('setEndDate', null);
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
date = this._newDate(date);
|
||||
date = this._UTCDateAsLocal(date);
|
||||
if (!isNaN(date)) {
|
||||
// Workaround for same issue as in _setMin.
|
||||
var curValue = $(el).bsDatepicker('getUTCDate');
|
||||
$(el).bsDatepicker('setEndDate', date);
|
||||
$(el).bsDatepicker('setUTCDate', curValue);
|
||||
}
|
||||
date = this._newDate(date);
|
||||
// If date parsing fails, do nothing
|
||||
if (date === null)
|
||||
return;
|
||||
|
||||
date = this._UTCDateAsLocal(date);
|
||||
if (isNaN(date))
|
||||
return;
|
||||
|
||||
// Workaround for same issue as in _setMin.
|
||||
var curValue = $(el).bsDatepicker('getUTCDate');
|
||||
$(el).bsDatepicker('setEndDate', date);
|
||||
$(el).bsDatepicker('setUTCDate', curValue);
|
||||
|
||||
// Workaround for same issue as in _setMin.
|
||||
if (typeof date.toDateString !== 'function') return;
|
||||
if (typeof curValue.toDateString !== 'function') return;
|
||||
if (date.toDateString() === curValue.toDateString()) {
|
||||
$(el).bsDatepicker('setEndDate', null);
|
||||
$(el).bsDatepicker('setUTCDate', curValue);
|
||||
$(el).bsDatepicker('setEndDate', date);
|
||||
}
|
||||
},
|
||||
// Given a date string of format yyyy-mm-dd, return a Date object with
|
||||
|
||||
@@ -864,13 +864,15 @@ var ShinyApp = function() {
|
||||
function getTabIndex($tabset, tabsetId) {
|
||||
// The 0 is to ensure this works for empty tabsetPanels as well
|
||||
var existingTabIds = [0];
|
||||
var leadingHref = "#tab-" + tabsetId + "-";
|
||||
// loop through all existing tabs, find the one with highest id
|
||||
// (since this is based on a numeric counter), and increment
|
||||
$tabset.find("> li").each(function() {
|
||||
var $tab = $(this).find("> a[data-toggle='tab']");
|
||||
if ($tab.length > 0) {
|
||||
var index = $tab.attr("href").replace(leadingHref, "");
|
||||
// remove leading url if it exists. (copy of bootstrap url stripper)
|
||||
var href = $tab.attr("href").replace(/.*(?=#[^\s]+$)/, '');
|
||||
// remove tab id to get the index
|
||||
var index = href.replace("#tab-" + tabsetId + "-", "");
|
||||
existingTabIds.push(Number(index));
|
||||
}
|
||||
});
|
||||
|
||||
2
tests/test-helpers/app1-standard/R/helperCap.R
Normal file
2
tests/test-helpers/app1-standard/R/helperCap.R
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
helper1 <- 123
|
||||
2
tests/test-helpers/app1-standard/R/helperLower.r
Normal file
2
tests/test-helpers/app1-standard/R/helperLower.r
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
helper2 <- "abc"
|
||||
1
tests/test-helpers/app1-standard/global.R
Normal file
1
tests/test-helpers/app1-standard/global.R
Normal file
@@ -0,0 +1 @@
|
||||
global <- "ABC"
|
||||
0
tests/test-helpers/app1-standard/server.R
Normal file
0
tests/test-helpers/app1-standard/server.R
Normal file
0
tests/test-helpers/app1-standard/ui.R
Normal file
0
tests/test-helpers/app1-standard/ui.R
Normal file
2
tests/test-helpers/app2-nested/R/helper.R
Normal file
2
tests/test-helpers/app2-nested/R/helper.R
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
helper1 <- 456
|
||||
2
tests/test-helpers/app2-nested/R/nested/helper.R
Normal file
2
tests/test-helpers/app2-nested/R/nested/helper.R
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
helper2 <- "def"
|
||||
8
tests/test-helpers/app2-nested/app.R
Normal file
8
tests/test-helpers/app2-nested/app.R
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
library(shiny)
|
||||
|
||||
ui <- fluidPage()
|
||||
|
||||
server <- function(input, output) {}
|
||||
|
||||
shinyApp(ui = ui, server = server)
|
||||
1
tests/test-helpers/app2-nested/global.R
Normal file
1
tests/test-helpers/app2-nested/global.R
Normal file
@@ -0,0 +1 @@
|
||||
stop("global.R should never be sourced alongside app.R")
|
||||
2
tests/test-helpers/app3-badglobal/R/helper.R
Normal file
2
tests/test-helpers/app3-badglobal/R/helper.R
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
helper1 <- 456
|
||||
2
tests/test-helpers/app3-badglobal/global.R
Normal file
2
tests/test-helpers/app3-badglobal/global.R
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
stop("I wasn't supposed to be sourced")
|
||||
0
tests/test-helpers/app4-both/app.R
Normal file
0
tests/test-helpers/app4-both/app.R
Normal file
1
tests/test-helpers/app4-both/r/lower.R
Normal file
1
tests/test-helpers/app4-both/r/lower.R
Normal file
@@ -0,0 +1 @@
|
||||
lowerHelper <- 123
|
||||
2
tests/test-helpers/app5-bad-supporting/R/helper.R
Normal file
2
tests/test-helpers/app5-bad-supporting/R/helper.R
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
stop("Imma crash")
|
||||
2
tests/test-helpers/app5-bad-supporting/global.R
Normal file
2
tests/test-helpers/app5-bad-supporting/global.R
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
happy <- TRUE
|
||||
@@ -49,8 +49,21 @@ contents_identical <- function(a, b) {
|
||||
TRUE
|
||||
}
|
||||
|
||||
|
||||
# Don't print out stack traces (which go to stderr)
|
||||
suppress_stacktrace <- function(expr) {
|
||||
capture.output(force(expr), type = "message")
|
||||
}
|
||||
|
||||
# Rewire copies the given function, f, and replaces any named
|
||||
# provided arguments in its execution.
|
||||
# Note #1: this only substitutes variables at the top-level function
|
||||
# call. Recursive calls back into this function will not have the
|
||||
# substitutions.
|
||||
# Note #2: this function won't work if the call includes the namespace.
|
||||
# i.e. `rewire(f, ls=function(x))` will not rewire a call to `base::ls()`.
|
||||
rewire <- function(f, ...) {
|
||||
orig_env <- environment(f)
|
||||
new_env <- list2env(list(...), parent = orig_env)
|
||||
environment(f) <- new_env
|
||||
f
|
||||
}
|
||||
|
||||
6
tests/testthat/print-reactiveValues.txt
Normal file
6
tests/testthat/print-reactiveValues.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
> x <- reactiveValues(x = 1, y = 2, z = 3)
|
||||
> x
|
||||
<ReactiveValues>
|
||||
Values: x, y, z
|
||||
Readonly: FALSE
|
||||
|
||||
166
tests/testthat/test-app.R
Normal file
166
tests/testthat/test-app.R
Normal file
@@ -0,0 +1,166 @@
|
||||
|
||||
context("app")
|
||||
|
||||
test_that("files are loaded into the right env", {
|
||||
renv <- new.env(parent=environment())
|
||||
genv <- new.env(parent=environment())
|
||||
|
||||
loadSupport("../test-helpers/app1-standard", renv=renv, globalrenv=genv)
|
||||
expect_equal(get("helper1", renv, inherits=FALSE), 123)
|
||||
expect_equal(get("helper2", renv, inherits=FALSE), "abc")
|
||||
|
||||
expect_equal(get("global", genv, inherits=FALSE), "ABC")
|
||||
})
|
||||
|
||||
test_that("Can suppress sourcing global.R", {
|
||||
# Confirm that things blow up if we source global.R
|
||||
expect_error(loadSupport(test_path("../test-helpers/app3-badglobal")))
|
||||
|
||||
# Shouldn't see an error now that we're suppressing global sourcing.
|
||||
renv <- loadSupport(test_path("../test-helpers/app3-badglobal"), globalrenv=NULL)
|
||||
|
||||
# But other helpers are still sourced
|
||||
expect_true(exists("helper1", envir=renv))
|
||||
})
|
||||
|
||||
test_that("nested helpers are not loaded", {
|
||||
loadSupport("../test-helpers/app2-nested", renv=environment(), globalrenv=NULL)
|
||||
expect_equal(helper1, 456)
|
||||
expect_false(exists("helper2"))
|
||||
})
|
||||
|
||||
test_that("app with both r/ and R/ prefers R/", {
|
||||
## App 4 already has a lower-case r/ directory. Try to create an upper.
|
||||
tryCatch(dir.create("../test-helpers/app4-both/R"),
|
||||
warning=function(w){testthat::skip("File system is not case-sensitive")})
|
||||
writeLines("upperHelper <- 'abc'", file.path("../test-helpers/app4-both/R", "upper.R"))
|
||||
|
||||
renv <- loadSupport("../test-helpers/app4-both")
|
||||
|
||||
expect_false(exists("lowerHelper", envir=renv))
|
||||
expect_equal(get("upperHelper", envir=renv), "abc")
|
||||
})
|
||||
|
||||
test_that("With ui/server.R, global.R is loaded before R/ helpers and into the right envs", {
|
||||
calls <- list()
|
||||
sourceStub <- function(...){
|
||||
calls[[length(calls)+1]] <<- list(...)
|
||||
NULL
|
||||
}
|
||||
|
||||
# Temporarily opt-in to R/ file autoloading
|
||||
orig <- getOption("shiny.autoload.r", NULL)
|
||||
options(shiny.autoload.r=TRUE)
|
||||
on.exit({options(shiny.autoload.r=orig)}, add=TRUE)
|
||||
|
||||
# + shinyAppDir_serverR
|
||||
# +--- sourceUTF8
|
||||
# +--+ loadSupport
|
||||
# | +--- sourceUTF8
|
||||
loadSpy <- rewire(loadSupport, sourceUTF8 = sourceStub)
|
||||
sad <- rewire(shinyAppDir_serverR, sourceUTF8 = sourceStub, loadSupport = loadSpy)
|
||||
|
||||
sa <- sad(normalizePath("../test-helpers/app1-standard"))
|
||||
sa$onStart()
|
||||
sa$onStop() # Close down to free up resources
|
||||
|
||||
# Should have seen three calls -- first to global then to the helpers
|
||||
expect_length(calls, 3)
|
||||
expect_match(calls[[1]][[1]], "/global\\.R$", perl=TRUE)
|
||||
expect_match(calls[[2]][[1]], "/helperCap\\.R$", perl=TRUE)
|
||||
expect_match(calls[[3]][[1]], "/helperLower\\.r$", perl=TRUE)
|
||||
|
||||
# Check environments
|
||||
# global.R loaded into the global env
|
||||
gEnv <- calls[[1]]$envir
|
||||
expect_identical(gEnv, globalenv())
|
||||
|
||||
# helpers are loaded into a child of the global env
|
||||
helperEnv1 <- calls[[2]]$envir
|
||||
helperEnv2 <- calls[[3]]$envir
|
||||
expect_identical(helperEnv1, helperEnv2)
|
||||
expect_identical(parent.env(helperEnv1), globalenv())
|
||||
|
||||
calls <- NULL
|
||||
# Source the server
|
||||
sa$serverFuncSource()
|
||||
expect_length(calls, 1)
|
||||
# server.R is sourced into a child environment of the helpers
|
||||
expect_match(calls[[1]][[1]], "/server\\.R$")
|
||||
expect_identical(parent.env(calls[[1]]$envir), helperEnv1)
|
||||
|
||||
calls <- NULL
|
||||
# Invoke the UI by simulating a request
|
||||
sa$httpHandler(list())
|
||||
expect_length(calls, 1)
|
||||
# ui.R is sourced into a child environment of the helpers
|
||||
expect_match(calls[[1]][[1]], "/ui\\.R$")
|
||||
expect_identical(parent.env(calls[[1]]$envir), helperEnv1)
|
||||
})
|
||||
|
||||
|
||||
test_that("Loading supporting R fils is opt-in", {
|
||||
calls <- list()
|
||||
sourceStub <- function(...){
|
||||
calls[[length(calls)+1]] <<- list(...)
|
||||
NULL
|
||||
}
|
||||
|
||||
# Temporarily unset autoloading option
|
||||
orig <- getOption("shiny.autoload.r", NULL)
|
||||
options(shiny.autoload.r=NULL)
|
||||
on.exit({options(shiny.autoload.r=orig)}, add=TRUE)
|
||||
|
||||
# + shinyAppDir_serverR
|
||||
# +--- sourceUTF8
|
||||
# +--+ loadSupport
|
||||
# | +--- sourceUTF8
|
||||
loadSpy <- rewire(loadSupport, sourceUTF8 = sourceStub)
|
||||
sad <- rewire(shinyAppDir_serverR, sourceUTF8 = sourceStub, loadSupport = loadSpy)
|
||||
|
||||
sa <- sad(normalizePath("../test-helpers/app1-standard"))
|
||||
sa$onStart()
|
||||
sa$onStop() # Close down to free up resources
|
||||
|
||||
# Should have seen one call from global.R -- helpers are disabled
|
||||
expect_length(calls, 1)
|
||||
expect_match(calls[[1]][[1]], "/global\\.R$", perl=TRUE)
|
||||
})
|
||||
|
||||
|
||||
test_that("app.R is loaded after R/ helpers and into the right envs", {
|
||||
calls <- list()
|
||||
sourceSpy <- function(...){
|
||||
calls[[length(calls)+1]] <<- list(...)
|
||||
do.call(sourceUTF8, list(...))
|
||||
}
|
||||
|
||||
# Temporarily opt-in to R/ file autoloading
|
||||
orig <- getOption("shiny.autoload.r", FALSE)
|
||||
options(shiny.autoload.r=TRUE)
|
||||
on.exit({options(shiny.autoload.r=orig)}, add=TRUE)
|
||||
|
||||
# + shinyAppDir_serverR
|
||||
# +--- sourceUTF8
|
||||
# +--+ loadSupport
|
||||
# | +--- sourceUTF8
|
||||
loadSpy <- rewire(loadSupport, sourceUTF8 = sourceSpy)
|
||||
sad <- rewire(shinyAppDir_appR, sourceUTF8 = sourceSpy, loadSupport = loadSpy)
|
||||
|
||||
sa <- sad("app.R", normalizePath("../test-helpers/app2-nested"))
|
||||
sa$onStart()
|
||||
sa$onStop() # Close down to free up resources
|
||||
|
||||
# Should have seen three calls -- first to two helpers then to app.R
|
||||
expect_length(calls, 2)
|
||||
expect_match(calls[[1]][[1]], "/helper\\.R$", perl=TRUE)
|
||||
expect_match(calls[[2]][[1]], "/app\\.R$", perl=TRUE)
|
||||
|
||||
# Check environments
|
||||
# helpers are loaded into a child of the global env
|
||||
helperEnv1 <- calls[[1]]$envir
|
||||
expect_identical(parent.env(helperEnv1), globalenv())
|
||||
|
||||
# app.R is sourced into a child environment of the helpers
|
||||
expect_identical(parent.env(calls[[2]]$envir), helperEnv1)
|
||||
})
|
||||
@@ -69,11 +69,28 @@ test_that("Repeated names for selectInput and radioButtons choices", {
|
||||
|
||||
|
||||
test_that("Choices are correctly assigned names", {
|
||||
# Empty non-list comes back with names
|
||||
expect_identical(
|
||||
choicesWithNames(numeric(0)),
|
||||
stats::setNames(list(), character(0))
|
||||
)
|
||||
# Empty list comes back with names
|
||||
expect_identical(
|
||||
choicesWithNames(list()),
|
||||
stats::setNames(list(), character(0))
|
||||
)
|
||||
# Empty character vector
|
||||
# An empty character vector isn't a sensical input, but we preserved this test
|
||||
# in the off chance that somebody relies on the existing behavior.
|
||||
expect_identical(
|
||||
choicesWithNames(c("")),
|
||||
stats::setNames(list(""), "")
|
||||
)
|
||||
# Single-item character vector
|
||||
expect_identical(
|
||||
choicesWithNames(c("foob")),
|
||||
list(foob="foob")
|
||||
)
|
||||
# Unnamed character vector
|
||||
expect_identical(
|
||||
choicesWithNames(c("a","b","3")),
|
||||
@@ -134,11 +151,6 @@ test_that("Choices are correctly assigned names", {
|
||||
choicesWithNames(list(A="a", "b", C=list("d", E="e"))),
|
||||
list(A="a", b="b", C=list(d="d", E="e"))
|
||||
)
|
||||
# Deeper nesting
|
||||
expect_identical(
|
||||
choicesWithNames(list(A="a", "b", C=list(D=list("e", "f"), G=c(H="h", "i")))),
|
||||
list(A="a", b="b", C=list(D=list(e="e", f="f"), G=list(H="h", i="i")))
|
||||
)
|
||||
# Error when sublist is unnamed
|
||||
expect_error(choicesWithNames(list(A="a", "b", list(1,2))))
|
||||
# Unnamed factor
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
context("options")
|
||||
|
||||
test_that("Local options", {
|
||||
# Clear out any options so we know we're starting fresh
|
||||
.globals$options <- list()
|
||||
|
||||
# Basic options
|
||||
shinyOptions(a = 1, b = 2)
|
||||
|
||||
|
||||
@@ -122,6 +122,12 @@ test_that("ReactiveValues", {
|
||||
expect_error(values$a <- 1)
|
||||
})
|
||||
|
||||
test_that("reactiveValues() has useful print method", {
|
||||
verify_output(test_path("print-reactiveValues.txt"), {
|
||||
x <- reactiveValues(x = 1, y = 2, z = 3)
|
||||
x
|
||||
})
|
||||
})
|
||||
|
||||
# Test for overreactivity. funcB has an indirect dependency on valueA (via
|
||||
# funcA) and also a direct dependency on valueA. When valueA changes, funcB
|
||||
@@ -1320,3 +1326,43 @@ test_that("Reactive contexts are not GC'd too early", {
|
||||
expect_identical(execCount(r), 3L)
|
||||
expect_false(r_finalized)
|
||||
})
|
||||
|
||||
|
||||
test_that("reactivePoll doesn't leak observer (#1548)", {
|
||||
i <- 0
|
||||
count <- reactivePoll(50, NULL,
|
||||
checkFunc = function() {
|
||||
i <<- i + 1
|
||||
i
|
||||
},
|
||||
valueFunc = function() i
|
||||
)
|
||||
|
||||
observe({
|
||||
count()
|
||||
})
|
||||
|
||||
while (i < 3) {
|
||||
Sys.sleep(0.05)
|
||||
shiny:::timerCallbacks$executeElapsed()
|
||||
shiny:::flushReact()
|
||||
}
|
||||
|
||||
# Removing the reference to count means that no one can use it anymore, and so
|
||||
# the finalizer should run. The finalizer sets a flag which will allow the
|
||||
# observer (which calls `checkFunc`) to run one more time; in that run, it
|
||||
# will remove itself.
|
||||
rm(count)
|
||||
gc()
|
||||
|
||||
# If the reactivePoll was cleaned up, then the first run of this loop will
|
||||
# increment i (bringing its value to 4), but in that run, the observer will
|
||||
# remove itself so subsequent runs will no longer run `checkFunc`.
|
||||
for (n in 1:3) {
|
||||
Sys.sleep(0.05)
|
||||
shiny:::timerCallbacks$executeElapsed()
|
||||
shiny:::flushReact()
|
||||
}
|
||||
|
||||
expect_equal(i, 3L)
|
||||
})
|
||||
|
||||
@@ -14,7 +14,8 @@ test_that("All man pages have an entry in staticdocs/index.r", {
|
||||
|
||||
# Known not to be indexed
|
||||
known_unindexed <- c("shiny-package", "stacktrace", "knitr_methods",
|
||||
"knitr_methods_htmltools", "deprecatedReactives")
|
||||
"pageWithSidebar", "headerPanel", "shiny.appobj",
|
||||
"deprecatedReactives")
|
||||
|
||||
# Read in topics from a staticdocs/index.r file
|
||||
get_indexed_topics <- function(index_path) {
|
||||
|
||||
2
tools/.gitignore
vendored
2
tools/.gitignore
vendored
@@ -1,2 +1,4 @@
|
||||
node_modules
|
||||
node_modules/
|
||||
node_modules*/
|
||||
temp_concat/
|
||||
|
||||
@@ -93,6 +93,7 @@ Updating web libraries
|
||||
======================
|
||||
|
||||
## babel-polyfill
|
||||
|
||||
To update the version of babel-polyfill:
|
||||
|
||||
* Check if there is a newer version available by running `yarn outdated babel-polyfill`. (If there's no output, then you have the latest version.)
|
||||
@@ -100,9 +101,9 @@ To update the version of babel-polyfill:
|
||||
* Edit R/shinyui.R. The `renderPage` function has an `htmlDependency` for
|
||||
`babel-polyfill`. Update this to the new version number.
|
||||
|
||||
# Updating and patching `bootstrap-datepicker`
|
||||
## Updating and patching `bootstrap-datepicker`
|
||||
|
||||
## Updating
|
||||
### Updating
|
||||
|
||||
[bootstrap-datepicker](https://github.com/uxsolutions/bootstrap-datepicker) can be updated with the script `updateBootstrapDatepicker.R`.
|
||||
|
||||
@@ -110,16 +111,36 @@ After updating, our patches to `bootstrap-datepicker` must be applied using the
|
||||
|
||||
After updating and applying patches, `yarn grunt` should be run per the instructions above in order to generate a minified JavaScript file.
|
||||
|
||||
## Making a new patch
|
||||
### Making a new patch
|
||||
|
||||
To create a new patch:
|
||||
|
||||
1. Make any necessary changes to files in `inst/www/shared/datepicker`
|
||||
1. **Do not commit your changes.**
|
||||
1. Instead, create a patch with a command like `git diff > tools/datepicker-patches/012-a-description.patch`. Patches are applied in alphabetic order (per `list.files`), so you should name your patch based on the last one in `tools/datepicker-patches` so that it's applied last.
|
||||
1. Add the new `.patch` file to the repo with a descriptive commit message
|
||||
1. Revert `bootstrap-datepicker` to its unpatched state by running `updateBootstrapDatepicker.R`
|
||||
1. Apply all patches, including the one you just made, by running `applyDatepickerPatches.R`
|
||||
1. Run `yarn grunt`
|
||||
1. Test your changes
|
||||
1. `git add` the new `.patch` and any resulting changes
|
||||
|
||||
|
||||
## Updating and patching ion.rangeSlider
|
||||
|
||||
### Updating
|
||||
|
||||
[ion.rangeSlider](https://github.com/IonDen/ion.rangeSlider) can be updated with the script `updateBootstrapDatepicker.R`. That script downloads a specific version of ion.rangeSlider and applies our patches in tools/ion.rangeSlider-patches.
|
||||
|
||||
After updating and applying patches, `yarn grunt` should be run per the instructions above in order to generate a minified JavaScript file.
|
||||
|
||||
### Making a new patch
|
||||
|
||||
To create a new patch:
|
||||
|
||||
1. Make any necessary changes to files in `inst/www/shared/ion.rangeSlider`
|
||||
1. **Do not commit your changes.**
|
||||
1. Instead, create a patch with a command like `git diff > tools/ion.rangeSlider-patches/0004-a-description.patch`. Patches are applied in alphabetic order (per `list.files`), so you should name your patch based on the last one in `tools/ion.rangeSlider-patches` so that it's applied last.
|
||||
1. Run `updateIonRangeSlider.R` to download the library and apply patches.
|
||||
1. Run `yarn grunt`
|
||||
1. Test your changes
|
||||
1. `git add` the new `.patch` and any resulting changes
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
diff --git a/inst/www/shared/ionrangeslider/css/ion.rangeSlider.skinShiny.css b/inst/www/shared/ionrangeslider/css/ion.rangeSlider.skinShiny.css
|
||||
new file mode 100644
|
||||
index 0000000..3b96e6b
|
||||
--- /dev/null
|
||||
+++ b/inst/www/shared/ionrangeslider/css/ion.rangeSlider.skinShiny.css
|
||||
@@ -0,0 +1,128 @@
|
||||
+/* Ion.RangeSlider, Shiny Skin
|
||||
+
|
||||
+// This skin has been modified for use with Shiny.
|
||||
+// It's based on the HTML5 skin, which doesn't require any sprites, but
|
||||
+// has been modified to have no gradients, and to have dimensions similar to
|
||||
+// the skinNice theme.
|
||||
+
|
||||
+// css version 2.0.0
|
||||
+// © RStudio, Inc, 2014
|
||||
+// © Denis Ineshin, 2014 https://github.com/IonDen
|
||||
+// © guybowden, 2014 https://github.com/guybowden
|
||||
+// ===================================================================================================================*/
|
||||
+
|
||||
+/* =====================================================================================================================
|
||||
+// Skin details */
|
||||
+
|
||||
+.irs {
|
||||
+ height: 40px;
|
||||
+}
|
||||
+.irs-with-grid {
|
||||
+ height: 60px;
|
||||
+}
|
||||
+.irs-line {
|
||||
+ height: 8px; top: 25px;
|
||||
+ background: #EEE;
|
||||
+ background: linear-gradient(to bottom, #DDD -50%, #FFF 150%); /* W3C */
|
||||
+ border: 1px solid #CCC;
|
||||
+ border-radius: 16px;
|
||||
+ -moz-border-radius: 16px;
|
||||
+}
|
||||
+ .irs-line-left {
|
||||
+ height: 8px;
|
||||
+ }
|
||||
+ .irs-line-mid {
|
||||
+ height: 8px;
|
||||
+ }
|
||||
+ .irs-line-right {
|
||||
+ height: 8px;
|
||||
+ }
|
||||
+
|
||||
+.irs-bar {
|
||||
+ height: 8px; top: 25px;
|
||||
+ border-top: 1px solid #428bca;
|
||||
+ border-bottom: 1px solid #428bca;
|
||||
+ background: #428bca;
|
||||
+}
|
||||
+ .irs-bar-edge {
|
||||
+ height: 8px; top: 25px;
|
||||
+ width: 14px;
|
||||
+ border: 1px solid #428bca;
|
||||
+ border-right: 0;
|
||||
+ background: #428bca;
|
||||
+ border-radius: 16px 0 0 16px;
|
||||
+ -moz-border-radius: 16px 0 0 16px;
|
||||
+ }
|
||||
+
|
||||
+.irs-shadow {
|
||||
+ height: 2px; top: 38px;
|
||||
+ background: #000;
|
||||
+ opacity: 0.3;
|
||||
+ border-radius: 5px;
|
||||
+ -moz-border-radius: 5px;
|
||||
+}
|
||||
+.lt-ie9 .irs-shadow {
|
||||
+ filter: alpha(opacity=30);
|
||||
+}
|
||||
+
|
||||
+.irs-slider {
|
||||
+ top: 17px;
|
||||
+ width: 22px; height: 22px;
|
||||
+ border: 1px solid #AAA;
|
||||
+ background: #DDD;
|
||||
+ border-radius: 27px;
|
||||
+ -moz-border-radius: 27px;
|
||||
+ box-shadow: 1px 1px 3px rgba(0,0,0,0.3);
|
||||
+ cursor: pointer;
|
||||
+}
|
||||
+
|
||||
+#irs-active-slider, .irs-slider:hover {
|
||||
+ background: #FFF;
|
||||
+}
|
||||
+
|
||||
+.irs-min, .irs-max {
|
||||
+ color: #333;
|
||||
+ font-size: 10px; line-height: 1.333;
|
||||
+ text-shadow: none;
|
||||
+ top: 0;
|
||||
+ padding: 1px 3px;
|
||||
+ background: rgba(0,0,0,0.1);
|
||||
+ border-radius: 3px;
|
||||
+ -moz-border-radius: 3px;
|
||||
+}
|
||||
+
|
||||
+.lt-ie9 .irs-min, .lt-ie9 .irs-max {
|
||||
+ background: #ccc;
|
||||
+}
|
||||
+
|
||||
+.irs-from, .irs-to, .irs-single {
|
||||
+ color: #fff;
|
||||
+ font-size: 11px; line-height: 1.333;
|
||||
+ text-shadow: none;
|
||||
+ padding: 1px 3px;
|
||||
+ background: #428bca;
|
||||
+ border-radius: 3px;
|
||||
+ -moz-border-radius: 3px;
|
||||
+}
|
||||
+.lt-ie9 .irs-from, .lt-ie9 .irs-to, .lt-ie9 .irs-single {
|
||||
+ background: #999;
|
||||
+}
|
||||
+
|
||||
+.irs-grid {
|
||||
+ height: 27px;
|
||||
+}
|
||||
+.irs-grid-pol {
|
||||
+ opacity: 0.5;
|
||||
+ background: #428bca;
|
||||
+}
|
||||
+.irs-grid-pol.small {
|
||||
+ background: #999;
|
||||
+}
|
||||
+
|
||||
+.irs-grid-text {
|
||||
+ bottom: 5px;
|
||||
+ color: #99a4ac;
|
||||
+}
|
||||
+
|
||||
+.irs-disabled {
|
||||
+}
|
||||
@@ -0,0 +1,20 @@
|
||||
diff --git a/inst/www/shared/ionrangeslider/js/ion.rangeSlider.js b/inst/www/shared/ionrangeslider/js/ion.rangeSlider.js
|
||||
index 2fe2c8d..89d204e 100644
|
||||
--- a/inst/www/shared/ionrangeslider/js/ion.rangeSlider.js
|
||||
+++ b/inst/www/shared/ionrangeslider/js/ion.rangeSlider.js
|
||||
@@ -816,6 +816,7 @@
|
||||
*/
|
||||
pointerDown: function (target, e) {
|
||||
e.preventDefault();
|
||||
+ e.stopPropagation();
|
||||
var x = e.pageX || e.originalEvent.touches && e.originalEvent.touches[0].pageX;
|
||||
if (e.button === 2) {
|
||||
return;
|
||||
@@ -859,6 +860,7 @@
|
||||
*/
|
||||
pointerClick: function (target, e) {
|
||||
e.preventDefault();
|
||||
+ e.stopPropagation();
|
||||
var x = e.pageX || e.originalEvent.touches && e.originalEvent.touches[0].pageX;
|
||||
if (e.button === 2) {
|
||||
return;
|
||||
@@ -0,0 +1,18 @@
|
||||
diff --git a/inst/www/shared/ionrangeslider/js/ion.rangeSlider.js b/inst/www/shared/ionrangeslider/js/ion.rangeSlider.js
|
||||
index 89d204ed..ae467f10 100644
|
||||
--- a/inst/www/shared/ionrangeslider/js/ion.rangeSlider.js
|
||||
+++ b/inst/www/shared/ionrangeslider/js/ion.rangeSlider.js
|
||||
@@ -1723,7 +1723,12 @@
|
||||
if (this.has_tab_index) {
|
||||
this.$cache.input.prop("tabindex", -1);
|
||||
} else {
|
||||
- this.$cache.input.removeProp("tabindex");
|
||||
+ try {
|
||||
+ this.$cache.input.removeProp("tabindex");
|
||||
+ } catch(e) {
|
||||
+ // Do nothing (PhantomJS can throw an error with the
|
||||
+ // above, #2587)
|
||||
+ }
|
||||
}
|
||||
|
||||
this.has_tab_index = !this.has_tab_index;
|
||||
88
tools/updateHtmltoolsMan.R
Normal file
88
tools/updateHtmltoolsMan.R
Normal file
@@ -0,0 +1,88 @@
|
||||
# source("tools/updateHtmltoolsMan.R")
|
||||
# Will update all man files that are re-exported from htmltools
|
||||
# Will save all aliases to `./R/htmltools.R` and document to enforce all re-exports
|
||||
|
||||
|
||||
local({
|
||||
|
||||
`%>%` <- magrittr::`%>%`
|
||||
|
||||
# pre document
|
||||
devtools::document()
|
||||
|
||||
namespace_line_count <- length(readLines(rprojroot::find_package_root_file("NAMESPACE")))
|
||||
|
||||
|
||||
htmltools_github_man_location <- "https://raw.githubusercontent.com/rstudio/htmltools/master/man/"
|
||||
|
||||
local_man_folder <- rprojroot::find_package_root_file("man")
|
||||
local_htmltools_r_file <- rprojroot::find_package_root_file("R/htmltools.R")
|
||||
|
||||
alias_list <- list()
|
||||
|
||||
update_htmltools_man_file <- function(man_file, ignore = NULL) {
|
||||
lines <- paste0(htmltools_github_man_location, man_file) %>%
|
||||
readLines() %>%
|
||||
{ .[-(1:2)] } # remove first two roxygen2 comments
|
||||
|
||||
man_file_path <- file.path(local_man_folder, man_file)
|
||||
lines %>%
|
||||
paste0(collapse = "\n") %>%
|
||||
writeLines(man_file_path)
|
||||
message("Updated: ", man_file_path)
|
||||
|
||||
alias_list[[man_file]] <<-
|
||||
lines[grepl("\\alias{", lines, fixed = TRUE)] %>%
|
||||
sub("\\alias{", "", ., fixed = TRUE) %>%
|
||||
sub("}$", "", .) %>%
|
||||
setdiff(ignore)
|
||||
}
|
||||
|
||||
update_htmltools_man_file("builder.Rd", "builder")
|
||||
update_htmltools_man_file("tag.Rd")
|
||||
update_htmltools_man_file("HTML.Rd")
|
||||
update_htmltools_man_file("include.Rd", "include")
|
||||
update_htmltools_man_file("singleton.Rd")
|
||||
update_htmltools_man_file("validateCssUnit.Rd")
|
||||
update_htmltools_man_file("htmlTemplate.Rd")
|
||||
update_htmltools_man_file("suppressDependencies.Rd")
|
||||
update_htmltools_man_file("withTags.Rd")
|
||||
|
||||
|
||||
alias_list %>%
|
||||
vapply(paste0, collapse = " ", character(1), USE.NAMES = FALSE) %>%
|
||||
paste0("#' @export ", .) %>%
|
||||
paste0(collapse = "\n") %>%
|
||||
paste0("#' @import htmltools\n", ., "\nNULL") %>%
|
||||
writeLines(local_htmltools_r_file)
|
||||
message("Updated: ", local_htmltools_r_file)
|
||||
|
||||
# document new functions
|
||||
devtools::document()
|
||||
namespace_line_count_new <- length(readLines(rprojroot::find_package_root_file("NAMESPACE")))
|
||||
|
||||
new_version <-
|
||||
"https://raw.githubusercontent.com/rstudio/htmltools/master/DESCRIPTION" %>%
|
||||
url() %>%
|
||||
read.dcf() %>%
|
||||
as.data.frame() %>%
|
||||
{.$Version[1]} %>%
|
||||
as.character()
|
||||
|
||||
message("\n")
|
||||
if (namespace_line_count_new == namespace_line_count) {
|
||||
message("The NAMESPACE exports did NOT change by copying in the `htmltools` man files")
|
||||
message()
|
||||
message("Possible `htmltools` version requirement to add to DESCRIPTION file:\nImports:\n htmltools (>= ", new_version, ")")
|
||||
} else {
|
||||
message("The NAMESPACE exports CHANGED by copying in the `htmltools` man files")
|
||||
message()
|
||||
message("`htmltools` version requirement to add to DESCRIPTION file:\nImports:\n htmltools (>= ", new_version, ")")
|
||||
message()
|
||||
message("Possible remote to add to the DESCRIPTION file:\nRemotes:\n rstudio/htmltools")
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
})
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user