mirror of
https://github.com/rstudio/shiny.git
synced 2026-01-11 16:08:19 -05:00
Compare commits
365 Commits
fix-factor
...
reactive_c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
550b679e61 | ||
|
|
8ada448c51 | ||
|
|
106ad74d2b | ||
|
|
0a6260259a | ||
|
|
78f9132eb3 | ||
|
|
15476ac32e | ||
|
|
17fb5b9eae | ||
|
|
fd27a0dfa2 | ||
|
|
5ffe69ec6c | ||
|
|
f5723b2a4d | ||
|
|
01491cc696 | ||
|
|
568a3f28cf | ||
|
|
02219df480 | ||
|
|
e006ca51ee | ||
|
|
86f651f3ec | ||
|
|
212b33a0ce | ||
|
|
6b7a121161 | ||
|
|
c89da718b1 | ||
|
|
eef3ae8387 | ||
|
|
0975a61725 | ||
|
|
0c53d54347 | ||
|
|
cbbb04cf69 | ||
|
|
120baf0a6e | ||
|
|
685dc7cc3a | ||
|
|
2fbb2ac77b | ||
|
|
2832db7aba | ||
|
|
18f2471d7c | ||
|
|
ea28f5a61b | ||
|
|
fe9cc6038e | ||
|
|
5ed335c499 | ||
|
|
fd04b97496 | ||
|
|
4c9d281b59 | ||
|
|
2ee06a7cbf | ||
|
|
cf2ba90b1d | ||
|
|
c69f34d1e2 | ||
|
|
ccfcc5d8b4 | ||
|
|
210c248264 | ||
|
|
e3258657d0 | ||
|
|
dbc518bf53 | ||
|
|
cdbdb4510e | ||
|
|
e7ec5e5ba4 | ||
|
|
03d8a7f296 | ||
|
|
480035c065 | ||
|
|
b32c18cf72 | ||
|
|
337a6b276a | ||
|
|
06cf1f9477 | ||
|
|
190cfd2b7a | ||
|
|
63035b4d66 | ||
|
|
6a11c8fcb1 | ||
|
|
33ffb006e3 | ||
|
|
162e7f63a9 | ||
|
|
bb581eeec4 | ||
|
|
272c555bc5 | ||
|
|
fb64caab23 | ||
|
|
6f2a74a46d | ||
|
|
ec65a74492 | ||
|
|
ba791c42fa | ||
|
|
5896667c36 | ||
|
|
003c949d38 | ||
|
|
d31394254c | ||
|
|
1a497e246c | ||
|
|
d24276aa54 | ||
|
|
6ed21a3e6b | ||
|
|
8066f9ce96 | ||
|
|
a0276ec1ce | ||
|
|
2ab925a24c | ||
|
|
78fbad7d8d | ||
|
|
89be4bdce9 | ||
|
|
d09a064471 | ||
|
|
2b18ca5a6c | ||
|
|
6bc2f18bbf | ||
|
|
fbb892d84e | ||
|
|
4efb7c20e4 | ||
|
|
4beb1f07a6 | ||
|
|
45e640e5f9 | ||
|
|
e84beffee3 | ||
|
|
e07c7483a7 | ||
|
|
34ec7bf5eb | ||
|
|
01b20a4829 | ||
|
|
45ea898da4 | ||
|
|
fd34c5070f | ||
|
|
6c409d96c1 | ||
|
|
0cbe4bb3d4 | ||
|
|
d04a990235 | ||
|
|
4747c87632 | ||
|
|
f57452c7bf | ||
|
|
9a8e2eb675 | ||
|
|
8ef7f3cbe2 | ||
|
|
de30a65f01 | ||
|
|
0bcf613195 | ||
|
|
89fd9004d0 | ||
|
|
b2be108db1 | ||
|
|
6102c44b70 | ||
|
|
327cdc8e41 | ||
|
|
0bc3613989 | ||
|
|
30cea871f9 | ||
|
|
5f332fe4db | ||
|
|
7ee7f2716b | ||
|
|
5e8c39cb1e | ||
|
|
ee355200b3 | ||
|
|
986fbe2254 | ||
|
|
32f93a2be1 | ||
|
|
ab79065c13 | ||
|
|
77171b7894 | ||
|
|
cce8ddb84f | ||
|
|
648b7e5911 | ||
|
|
67a66fdc93 | ||
|
|
5fbaa26d05 | ||
|
|
1f4a3c4fd2 | ||
|
|
959dc7ffd4 | ||
|
|
0e34221cac | ||
|
|
0cad13b3a3 | ||
|
|
0776f71ca3 | ||
|
|
5a74e369ce | ||
|
|
799c5ac662 | ||
|
|
1080cf0ef4 | ||
|
|
867d49e3fb | ||
|
|
c7be406099 | ||
|
|
37257e77ce | ||
|
|
270d9ff0fc | ||
|
|
34b48598d9 | ||
|
|
5105ecb148 | ||
|
|
f47b151458 | ||
|
|
d3f15a58fc | ||
|
|
42f6adb7fa | ||
|
|
263f8a8e7d | ||
|
|
3a42d30cfd | ||
|
|
9275217a5a | ||
|
|
1fed19ad68 | ||
|
|
6a8a78abd1 | ||
|
|
de69f51084 | ||
|
|
c81a3f39fd | ||
|
|
6fcb925e34 | ||
|
|
8823b7280a | ||
|
|
ebadad97a8 | ||
|
|
a095c39626 | ||
|
|
fb9bcb44c3 | ||
|
|
38f593450a | ||
|
|
6d44f2c5cb | ||
|
|
d1786a64c4 | ||
|
|
616ae99c0b | ||
|
|
4d2ff80788 | ||
|
|
005295fd4c | ||
|
|
d6b46f8243 | ||
|
|
bac35e8f1b | ||
|
|
a003c4da85 | ||
|
|
0ae8e4fe8a | ||
|
|
d3667dfc77 | ||
|
|
54c5467dc6 | ||
|
|
d01f0300a5 | ||
|
|
bff207008f | ||
|
|
ed739f95ff | ||
|
|
bb4de1336c | ||
|
|
f7205558d2 | ||
|
|
1318544ecf | ||
|
|
a81c161434 | ||
|
|
73acdc755f | ||
|
|
dd84ea8fda | ||
|
|
a2a4e40821 | ||
|
|
509f54d68c | ||
|
|
27ce460ea4 | ||
|
|
116794ad77 | ||
|
|
89feba870d | ||
|
|
2a980601c0 | ||
|
|
e1fd8ae910 | ||
|
|
9cb415008c | ||
|
|
26ba9bf94a | ||
|
|
fb091ca195 | ||
|
|
99a7dca3ce | ||
|
|
a1a03d94be | ||
|
|
85a2d41a72 | ||
|
|
89bd7e9011 | ||
|
|
ececdf42a7 | ||
|
|
2cf03de8b8 | ||
|
|
c8daa1730b | ||
|
|
d195b595dd | ||
|
|
ff3f7adff2 | ||
|
|
37781a9df7 | ||
|
|
ca1c60e00e | ||
|
|
649f382291 | ||
|
|
103a35c81b | ||
|
|
5af341bfdb | ||
|
|
7c7110cd83 | ||
|
|
c4ea489bff | ||
|
|
60b3b6ff03 | ||
|
|
1510dca065 | ||
|
|
2c49375928 | ||
|
|
f9fc22c48b | ||
|
|
8d14e7ab04 | ||
|
|
8f2a28a1f2 | ||
|
|
e8fb1faec0 | ||
|
|
0e4874c412 | ||
|
|
933630af28 | ||
|
|
ff87098102 | ||
|
|
6513a86bbd | ||
|
|
97e296c5d5 | ||
|
|
9f87adf4e8 | ||
|
|
6470b3f08c | ||
|
|
d1ba84525e | ||
|
|
05ad66c464 | ||
|
|
c41d38bf61 | ||
|
|
b155e8480b | ||
|
|
e94f687573 | ||
|
|
5883082d01 | ||
|
|
75b53ffda1 | ||
|
|
a8057b96f3 | ||
|
|
a89e809498 | ||
|
|
02f7a4fdc9 | ||
|
|
7c7c22a597 | ||
|
|
860fa525a2 | ||
|
|
9f0e38a28a | ||
|
|
f834b7befb | ||
|
|
7f3a45fb5b | ||
|
|
b0953e810b | ||
|
|
52a86012e5 | ||
|
|
2a06fe6baf | ||
|
|
6e688d2175 | ||
|
|
b610fd1f56 | ||
|
|
a4730096f4 | ||
|
|
6a02439944 | ||
|
|
b889b0d2b0 | ||
|
|
ba5733e4a4 | ||
|
|
2e0221ecfd | ||
|
|
aeded79544 | ||
|
|
c0a7958e77 | ||
|
|
431b194ec2 | ||
|
|
29d24d7e08 | ||
|
|
3b04c642ae | ||
|
|
609fc5b0c0 | ||
|
|
2a8c79b577 | ||
|
|
043316e40f | ||
|
|
c9d8b987d4 | ||
|
|
33c5a5c665 | ||
|
|
29c90ba163 | ||
|
|
8c19450b10 | ||
|
|
89c97458c4 | ||
|
|
02be516902 | ||
|
|
47ada300ea | ||
|
|
6f9c621774 | ||
|
|
324d9195c3 | ||
|
|
0310fe3b68 | ||
|
|
7144a6e4b7 | ||
|
|
1c8071a96f | ||
|
|
4ad115e024 | ||
|
|
f11d754cfe | ||
|
|
65019ce96f | ||
|
|
90e8fb2a57 | ||
|
|
ff5377da9e | ||
|
|
7aee84eb05 | ||
|
|
c0a7a6d0d6 | ||
|
|
29c48471f2 | ||
|
|
229e56464b | ||
|
|
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 | ||
|
|
1685e1c310 | ||
|
|
332f5a1266 | ||
|
|
99ac85f06a | ||
|
|
fc30ad0935 | ||
|
|
aadf2eb609 | ||
|
|
68f778e423 | ||
|
|
0066cff652 | ||
|
|
f872a0c80a | ||
|
|
68d67a8194 | ||
|
|
756ac1514c | ||
|
|
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 |
@@ -20,3 +20,4 @@
|
||||
^revdep$
|
||||
^TODO-promises.md$
|
||||
^manualtests$
|
||||
^\.github$
|
||||
|
||||
8
CONTRIBUTING.md → .github/CONTRIBUTING.md
vendored
8
CONTRIBUTING.md → .github/CONTRIBUTING.md
vendored
@@ -2,13 +2,15 @@ We welcome contributions to the **shiny** package. To submit a contribution:
|
||||
|
||||
1. [Fork](https://github.com/rstudio/shiny/fork) the repository and make your changes.
|
||||
|
||||
2. Ensure that you have signed the [individual](https://rstudioblog.files.wordpress.com/2017/05/rstudio_individual_contributor_agreement.pdf) or [corporate](https://rstudioblog.files.wordpress.com/2017/05/rstudio_corporate_contributor_agreement.pdf) contributor agreement as appropriate. You can send the signed copy to jj@rstudio.com.
|
||||
2. Submit a [pull request](https://help.github.com/articles/using-pull-requests).
|
||||
|
||||
3. Submit a [pull request](https://help.github.com/articles/using-pull-requests).
|
||||
3. Ensure that you have signed the contributor license agreement. It will appear as a "Check"
|
||||
on your PR and a comment from "CLAassistant" will also appear explaining whether you have
|
||||
yet to sign. After you sign, you can click the "Recheck" link in that comment and the check
|
||||
will flip to reflect that you've signed.
|
||||
|
||||
We generally do not merge pull requests that update included web libraries (such as Bootstrap or jQuery) because it is difficult for us to verify that the update is done correctly; we prefer to update these libraries ourselves.
|
||||
|
||||
|
||||
## How to make changes
|
||||
|
||||
Before you submit a pull request, please do the following:
|
||||
17
.travis.yml
17
.travis.yml
@@ -5,20 +5,21 @@ matrix:
|
||||
r: release
|
||||
r_packages:
|
||||
- devtools
|
||||
- roxygen2
|
||||
- rprojroot
|
||||
script: ./tools/checkDocsCurrent.sh
|
||||
- name: "Javascript check"
|
||||
language: node_js
|
||||
cache: yarn
|
||||
script: ./tools/checkJSCurrent.sh
|
||||
node_js:
|
||||
- "10"
|
||||
- name: "Old Release Check"
|
||||
r: oldrel
|
||||
- name: "Current Release Check"
|
||||
r: release
|
||||
- name: "Development Release Check"
|
||||
r: devel
|
||||
- "12"
|
||||
- r: 3.2
|
||||
- r: 3.3
|
||||
- r: 3.4
|
||||
- r: 3.5
|
||||
- r: release
|
||||
- r: devel
|
||||
|
||||
sudo: false
|
||||
cache: packages
|
||||
notifications:
|
||||
|
||||
29
DESCRIPTION
29
DESCRIPTION
@@ -1,7 +1,7 @@
|
||||
Package: shiny
|
||||
Type: Package
|
||||
Title: Web Application Framework for R
|
||||
Version: 1.3.2.9001
|
||||
Version: 1.4.0.9002
|
||||
Authors@R: c(
|
||||
person("Winston", "Chang", role = c("aut", "cre"), email = "winston@rstudio.com"),
|
||||
person("Joe", "Cheng", role = "aut", email = "joe@rstudio.com"),
|
||||
@@ -65,20 +65,21 @@ Depends:
|
||||
Imports:
|
||||
utils,
|
||||
grDevices,
|
||||
httpuv (>= 1.5.0),
|
||||
httpuv (>= 1.5.2),
|
||||
mime (>= 0.3),
|
||||
jsonlite (>= 0.9.16),
|
||||
xtable,
|
||||
digest,
|
||||
htmltools (>= 0.3.6),
|
||||
htmltools (>= 0.4.0.9001),
|
||||
R6 (>= 2.0),
|
||||
sourcetools,
|
||||
later (>= 0.7.2),
|
||||
promises (>= 1.0.1),
|
||||
later (>= 1.0.0),
|
||||
promises (>= 1.1.0),
|
||||
tools,
|
||||
crayon,
|
||||
rlang (>= 0.4.0),
|
||||
fastmap (>= 0.0.0.9001)
|
||||
fastmap (>= 1.0.0),
|
||||
withr
|
||||
Suggests:
|
||||
datasets,
|
||||
Cairo (>= 1.5-5),
|
||||
@@ -88,7 +89,13 @@ Suggests:
|
||||
rmarkdown,
|
||||
ggplot2,
|
||||
reactlog (>= 1.0.0),
|
||||
magrittr
|
||||
magrittr,
|
||||
shinytest,
|
||||
yaml,
|
||||
future,
|
||||
dygraphs
|
||||
Remotes:
|
||||
rstudio/htmltools
|
||||
URL: http://shiny.rstudio.com
|
||||
BugReports: https://github.com/rstudio/shiny/issues
|
||||
Collate:
|
||||
@@ -96,6 +103,7 @@ Collate:
|
||||
'bookmark-state-local.R'
|
||||
'stack.R'
|
||||
'bookmark-state.R'
|
||||
'bootstrap-deprecated.R'
|
||||
'bootstrap-layout.R'
|
||||
'globals.R'
|
||||
'conditions.R'
|
||||
@@ -139,6 +147,8 @@ Collate:
|
||||
'jqueryui.R'
|
||||
'middleware-shiny.R'
|
||||
'middleware.R'
|
||||
'timer.R'
|
||||
'mock-session.R'
|
||||
'modal.R'
|
||||
'modules.R'
|
||||
'notifications.R'
|
||||
@@ -160,8 +170,9 @@ Collate:
|
||||
'snapshot.R'
|
||||
'tar.R'
|
||||
'test-export.R'
|
||||
'timer.R'
|
||||
'test-module.R'
|
||||
'test.R'
|
||||
'update-input.R'
|
||||
RoxygenNote: 6.1.1
|
||||
RoxygenNote: 7.1.0
|
||||
Encoding: UTF-8
|
||||
Roxygen: list(markdown = TRUE)
|
||||
|
||||
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
|
||||
|
||||
24
NAMESPACE
24
NAMESPACE
@@ -1,15 +1,18 @@
|
||||
# Generated by roxygen2: do not edit by hand
|
||||
|
||||
S3method("$",mockclientdata)
|
||||
S3method("$",reactivevalues)
|
||||
S3method("$",session_proxy)
|
||||
S3method("$",shinyoutput)
|
||||
S3method("$<-",reactivevalues)
|
||||
S3method("$<-",session_proxy)
|
||||
S3method("$<-",shinyoutput)
|
||||
S3method("[",mockclientdata)
|
||||
S3method("[",reactivevalues)
|
||||
S3method("[",shinyoutput)
|
||||
S3method("[<-",reactivevalues)
|
||||
S3method("[<-",shinyoutput)
|
||||
S3method("[[",mockclientdata)
|
||||
S3method("[[",reactivevalues)
|
||||
S3method("[[",session_proxy)
|
||||
S3method("[[",shinyoutput)
|
||||
@@ -26,12 +29,15 @@ 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..)
|
||||
export(..stacktraceon..)
|
||||
export(HTML)
|
||||
export(MockShinySession)
|
||||
export(NS)
|
||||
export(Progress)
|
||||
export(a)
|
||||
@@ -132,12 +138,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)
|
||||
@@ -145,6 +146,7 @@ export(maskReactiveContext)
|
||||
export(memoryCache)
|
||||
export(modalButton)
|
||||
export(modalDialog)
|
||||
export(moduleServer)
|
||||
export(navbarMenu)
|
||||
export(navbarPage)
|
||||
export(navlistPanel)
|
||||
@@ -195,6 +197,7 @@ export(registerInputHandler)
|
||||
export(removeInputHandler)
|
||||
export(removeModal)
|
||||
export(removeNotification)
|
||||
export(removeResourcePath)
|
||||
export(removeTab)
|
||||
export(removeUI)
|
||||
export(renderCachedPlot)
|
||||
@@ -207,12 +210,14 @@ export(renderText)
|
||||
export(renderUI)
|
||||
export(repeatable)
|
||||
export(req)
|
||||
export(resourcePaths)
|
||||
export(restoreInput)
|
||||
export(runApp)
|
||||
export(runExample)
|
||||
export(runGadget)
|
||||
export(runGist)
|
||||
export(runGitHub)
|
||||
export(runTests)
|
||||
export(runUrl)
|
||||
export(safeError)
|
||||
export(selectInput)
|
||||
@@ -253,9 +258,13 @@ export(tag)
|
||||
export(tagAppendAttributes)
|
||||
export(tagAppendChild)
|
||||
export(tagAppendChildren)
|
||||
export(tagGetAttribute)
|
||||
export(tagHasAttribute)
|
||||
export(tagList)
|
||||
export(tagSetChildren)
|
||||
export(tags)
|
||||
export(testModule)
|
||||
export(testServer)
|
||||
export(textAreaInput)
|
||||
export(textInput)
|
||||
export(textOutput)
|
||||
@@ -305,3 +314,6 @@ importFrom(fastmap,is.key_missing)
|
||||
importFrom(fastmap,key_missing)
|
||||
importFrom(grDevices,dev.cur)
|
||||
importFrom(grDevices,dev.set)
|
||||
importFrom(promises,"%...!%")
|
||||
importFrom(promises,"%...>%")
|
||||
importFrom(withr,with_options)
|
||||
|
||||
85
NEWS.md
85
NEWS.md
@@ -1,26 +1,84 @@
|
||||
shiny 1.3.2.9001
|
||||
=======
|
||||
shiny 1.4.0.9001
|
||||
===========
|
||||
|
||||
## Changes
|
||||
## Full changelog
|
||||
|
||||
* Resolved [#1433](https://github.com/rstudio/shiny/issues/1433): `plotOutput()`'s coordmap info now includes discrete axis limits for **ggplot2** plots. As a result, any **shinytest** tests that contain **ggplot2** plots with discrete axes (that were recorded before this change) will now report differences that can safely be updated. This new coordmap info was added to correctly infer what data points are within an input brush and/or near input click/hover in scenarios where a non-trivial discrete axis scale is involved (e.g., whenever `scale_[x/y]_discrete(limits = ...)` and/or free scales across multiple discrete axes are used). ([#2410](https://github.com/rstudio/shiny/pull/2410))
|
||||
### Breaking changes
|
||||
|
||||
### New features
|
||||
|
||||
* The new `moduleServer` function provides a simpler interface for creating and using modules. ([#2773](https://github.com/rstudio/shiny/pull/2773))
|
||||
|
||||
### Minor new features and improvements
|
||||
|
||||
* Fixed [#2042](https://github.com/rstudio/shiny/issues/2042), [#2628](https://github.com/rstudio/shiny/issues/2628): In a `dateInput` and `dateRangeInput`, disabled months and years are now a lighter gray, to make it easier to see that they are disabled. ([#2690](https://github.com/rstudio/shiny/pull/2690))
|
||||
|
||||
* `getCurrentOutputInfo()` previously threw an error when called from outside of an output; now it returns `NULL`. ([#2707](https://github.com/rstudio/shiny/pull/2707))
|
||||
|
||||
* Added a label to observer that auto-reloads `R/` directory to avoid confusion when using `reactlog`. ([#58](https://github.com/rstudio/reactlog/issues/58))
|
||||
|
||||
* `getDefaultReactiveDomain()` can now be called inside a `session$onSessionEnded` callback and will return the calling `session` information. ([#2757](https://github.com/rstudio/shiny/pull/2757))
|
||||
|
||||
* Added a `'function'` class to `reactive()` and `reactiveVal()` objects. ([#2793](https://github.com/rstudio/shiny/pull/2793))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* Fixed [#2606](https://github.com/rstudio/shiny/issues/2606): `debounce()` would not work properly if the code in the reactive expression threw an error on the first run. ([#2652](https://github.com/rstudio/shiny/pull/2652))
|
||||
|
||||
* Fixed [#2653](https://github.com/rstudio/shiny/issues/2653): The `dataTableOutput()` could have incorrect output if certain characters were in the column names. ([#2658](https://github.com/rstudio/shiny/pull/2658))
|
||||
|
||||
### Documentation Updates
|
||||
|
||||
|
||||
shiny 1.4.0.1
|
||||
===========
|
||||
|
||||
Minor patch release to account for changes to the grid package that will be upcoming in the R 4.0 release ([#2776](https://github.com/rstudio/shiny/pull/2776)).
|
||||
|
||||
|
||||
shiny 1.4.0
|
||||
===========
|
||||
|
||||
## Full changelog
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Resolved [#2554](https://github.com/rstudio/shiny/issues/2554): Upgraded jQuery from v.1.12.4 to v3.4.1 and bootstrap from v3.3.7 to v3.4.1. ([#2557](https://github.com/rstudio/shiny/pull/2557)). Since the jQuery upgrade may introduce breaking changes to user code, there is an option to switch back to the old version by setting `options(shiny.jquery.version = 1)`. If you've hard-coded `shared/jquery[.min].js` in the HTML of your Shiny app, in order to downgrade, you'll have to change that filepath to `shared/legacy/jquery[.min].js`.
|
||||
|
||||
### Improvements
|
||||
|
||||
* Resolved [#1433](https://github.com/rstudio/shiny/issues/1433): `plotOutput()`'s coordmap info now includes discrete axis limits for **ggplot2** plots. As a result, any **shinytest** tests that contain **ggplot2** plots with discrete axes (that were recorded before this change) will now report differences that can safely be updated. This new coordmap info was added to correctly infer what data points are within an input brush and/or near input click/hover in scenarios where a non-trivial discrete axis scale is involved (e.g., whenever `scale_[x/y]_discrete(limits = ...)` and/or free scales across multiple discrete axes are used). ([#2410](https://github.com/rstudio/shiny/pull/2410))
|
||||
|
||||
* 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))
|
||||
|
||||
* 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))
|
||||
|
||||
* Resolved [#2515](https://github.com/rstudio/shiny/issues/2515): `selectInput()` now deals appropriately with named factors. ([#2524](https://github.com/rstudio/shiny/pull/2524))
|
||||
* Added `resourcePaths()` and `removeResourcePaths()` functions. ([#2459](https://github.com/rstudio/shiny/pull/2459))
|
||||
|
||||
* 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 [#2478](https://github.com/rstudio/shiny/issues/2478): `cmd + shift + f3` and `ctrl + shift + f3` can now be used to add a reactlog mark. If reactlog keybindings are used and the reactlog is not enabled, an error page is displayed showing how to enable reactlog recordings. ([#2560](https://github.com/rstudio/shiny/pull/2560))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* 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)
|
||||
|
||||
* 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))
|
||||
|
||||
* Resolved [#2515](https://github.com/rstudio/shiny/issues/2515): `selectInput()` and `selectizeInput()` now deal appropriately with named factors. Note that `updateSelectInput()` and `updateSelectizeInput()` **do not** yet handle factors; their behavior is unchanged. ([#2524](https://github.com/rstudio/shiny/pull/2524), [#2540](https://github.com/rstudio/shiny/pull/2540), [#2625](https://github.com/rstudio/shiny/pull/2625))
|
||||
|
||||
* 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))
|
||||
|
||||
* 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,16 +89,23 @@ 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 [#2598](https://github.com/rstudio/shiny/issues/2598): Showcase files don't appear with a wide window. ([#2582](https://github.com/rstudio/shiny/pull/2582))
|
||||
|
||||
* 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.
|
||||
|
||||
|
||||
shiny 1.3.2
|
||||
===========
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* Fixed [#2285](https://github.com/rstudio/shiny/issues/2285), [#2288](https://github.com/rstudio/shiny/issues/2288): Static CSS/JS resources in subapps in R Markdown documents did not render properly. ([#2386](https://github.com/rstudio/shiny/pull/2386))
|
||||
* Fixed [#2385](https://github.com/rstudio/shiny/issues/2385): Static CSS/JS resources in subapps in R Markdown documents did not render properly. ([#2386](https://github.com/rstudio/shiny/pull/2386))
|
||||
|
||||
* Fixed [#2280](https://github.com/rstudio/shiny/issues/2280): Shiny applications that used a www/index.html file did not serve up the index file. ([#2382](https://github.com/rstudio/shiny/pull/2382))
|
||||
|
||||
@@ -132,6 +197,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)
|
||||
@@ -602,7 +669,7 @@ There are many more minor features, small improvements, and bug fixes than we ca
|
||||
|
||||
* **Code Diagnostics**: if there is an error parsing `ui.R`, `server.R`, `app.R`, or `global.R`, Shiny will search the code for missing commas, extra commas, and unmatched braces, parens, and brackets, and will print out messages pointing out those problems. ([#1126](https://github.com/rstudio/shiny/pull/1126))
|
||||
|
||||
* **Reactlog visualization**: by default, the [`showReactLog()` function](http://shiny.rstudio.com/reference/shiny/latest/showReactLog.html) (which brings up the reactive graph) also displays the time that each reactive and observer were active for:
|
||||
* **Reactlog visualization**: by default, the [`showReactLog()` function](http://shiny.rstudio.com/reference/shiny/latest/reactlog.html) (which brings up the reactive graph) also displays the time that each reactive and observer were active for:
|
||||
|
||||
<p align="center">
|
||||
<img src="http://shiny.rstudio.com/images/reactlog.png" alt="modal-dialog" width="75%"/>
|
||||
|
||||
144
R/app.R
144
R/app.R
@@ -13,8 +13,13 @@
|
||||
#' object to `print()` or [runApp()].
|
||||
#'
|
||||
#' @param ui The UI definition of the app (for example, a call to
|
||||
#' `fluidPage()` with nested controls)
|
||||
#' @param server A server function
|
||||
#' `fluidPage()` with nested controls).
|
||||
#'
|
||||
#' If bookmarking is enabled (see `enableBookmarking`), this must be
|
||||
#' a single argument function that returns the UI definition.
|
||||
#' @param server A function with three parameters: `input`, `output`, and
|
||||
#' `session`. The function is called once for each session ensuring that each
|
||||
#' app is independent.
|
||||
#' @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.
|
||||
@@ -28,11 +33,9 @@
|
||||
#' request. Note that the entire request path must match the regular
|
||||
#' expression in order for the match to be considered successful.
|
||||
#' @param enableBookmarking Can be one of `"url"`, `"server"`, or
|
||||
#' `"disable"`. This is equivalent to calling the
|
||||
#' [enableBookmarking()] function just before calling
|
||||
#' `shinyApp()`. With the default value (`NULL`), the app will
|
||||
#' respect the setting from any previous calls to `enableBookmarking()`.
|
||||
#' See [enableBookmarking()] for more information.
|
||||
#' `"disable"`. The default value, `NULL`, will respect the setting from
|
||||
#' any previous calls to [enableBookmarking()]. See [enableBookmarking()]
|
||||
#' for more information on bookmarking your app.
|
||||
#' @return An object that represents the app. Printing the object or passing it
|
||||
#' to [runApp()] will run the app.
|
||||
#'
|
||||
@@ -68,10 +71,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 +142,21 @@ 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.
|
||||
if (getOption("shiny.autoload.r", TRUE)) {
|
||||
# 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
|
||||
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 +167,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 +197,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 +228,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", TRUE)) {
|
||||
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)
|
||||
@@ -265,7 +284,8 @@ initAutoReloadMonitor <- function(dir) {
|
||||
".*\\.(r|html?|js|css|png|jpe?g|gif)$")
|
||||
|
||||
lastValue <- NULL
|
||||
obs <- observe({
|
||||
observeLabel <- paste0("File Auto-Reload - '", basename(dir), "'")
|
||||
obs <- observe(label = observeLabel, {
|
||||
files <- sort(list.files(dir, pattern = filePattern, recursive = TRUE,
|
||||
ignore.case = TRUE))
|
||||
times <- file.info(files)$mtime
|
||||
@@ -288,18 +308,81 @@ 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.
|
||||
#'
|
||||
#' Since Shiny 1.5.0, this function is called by default when running an
|
||||
#' application. If it causes problems, there are two ways to opt out. You can
|
||||
#' either place a file named `_disable_autoload.R` in your R/ directory, or
|
||||
#' set `options(shiny.autoload.r=FALSE)`. If you set this option, it will
|
||||
#' affect any application that runs later in the same R session, potentially
|
||||
#' breaking it, so after running your application, you should unset option with
|
||||
#' `options(shiny.autoload.r=NULL)`
|
||||
#'
|
||||
#' @details The files are sourced in alphabetical order (as determined by
|
||||
#' [list.files]). `global.R` is evaluated before the supporting R files in the
|
||||
#' `R/` directory.
|
||||
#' @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")
|
||||
|
||||
disabled <- list.files(helpersDir, pattern="^_disable_autoload\\.r$", recursive=FALSE, ignore.case=TRUE)
|
||||
if (length(disabled) > 0){
|
||||
message("R/_disable_autoload.R detected; not loading the R/ directory automatically")
|
||||
return(invisible(renv))
|
||||
}
|
||||
|
||||
helpers <- list.files(helpersDir, pattern="\\.[rR]$", recursive=FALSE, full.names=TRUE)
|
||||
|
||||
if (length(helpers) > 0){
|
||||
message("Automatically loading ", length(helpers), " .R file",
|
||||
ifelse(length(helpers) != 1, "s", ""),
|
||||
" found in the R/ directory.\nSee https://rstd.io/shiny-autoload for more info.")
|
||||
}
|
||||
|
||||
lapply(helpers, sourceUTF8, envir=renv)
|
||||
|
||||
invisible(renv)
|
||||
}
|
||||
|
||||
# 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.
|
||||
if (getOption("shiny.autoload.r", TRUE)) {
|
||||
# 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 {
|
||||
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 +425,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", TRUE)) {
|
||||
loadSupport(appDir, renv=sharedEnv, globalrenv=NULL)
|
||||
}
|
||||
monitorHandle <<- initAutoReloadMonitor(appDir)
|
||||
if (!is.null(appObj()$onStart)) appObj()$onStart()
|
||||
}
|
||||
@@ -376,26 +463,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 +499,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 +520,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 +574,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 +610,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 +622,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({
|
||||
|
||||
47
R/bootstrap-deprecated.R
Normal file
47
R/bootstrap-deprecated.R
Normal file
@@ -0,0 +1,47 @@
|
||||
#' 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)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -28,7 +28,8 @@
|
||||
#' Shiny-Application-Layout-Guide](http://shiny.rstudio.com/articles/layout-guide.html) for additional details on laying out fluid
|
||||
#' pages.
|
||||
#'
|
||||
#' @seealso [column()], [sidebarLayout()]
|
||||
#' @family layout functions
|
||||
#' @seealso [column()]
|
||||
#'
|
||||
#' @examples
|
||||
#' ## Only run examples in interactive R sessions
|
||||
@@ -130,6 +131,8 @@ fluidRow <- function(...) {
|
||||
#' Shiny Application Layout Guide](http://shiny.rstudio.com/articles/layout-guide.html) for additional details on laying out fixed
|
||||
#' pages.
|
||||
#'
|
||||
#' @family layout functions
|
||||
#'
|
||||
#' @seealso [column()]
|
||||
#'
|
||||
#' @examples
|
||||
@@ -228,8 +231,12 @@ column <- function(width, ..., offset = 0) {
|
||||
stop("column width must be between 1 and 12")
|
||||
|
||||
colClass <- paste0("col-sm-", width)
|
||||
if (offset > 0)
|
||||
colClass <- paste0(colClass, " col-sm-offset-", offset)
|
||||
if (offset > 0) {
|
||||
# offset-md-x is for bootstrap 4 forward compat
|
||||
# (every size tier has been bumped up one level)
|
||||
# https://github.com/twbs/bootstrap/blob/74b8fe7/docs/4.3/migration/index.html#L659
|
||||
colClass <- paste0(colClass, " offset-md-", offset, " col-sm-offset-", offset)
|
||||
}
|
||||
div(class = colClass, ...)
|
||||
}
|
||||
|
||||
@@ -243,7 +250,6 @@ column <- function(width, ..., offset = 0) {
|
||||
#' `title` tag within the head. You can also specify a page title
|
||||
#' explicitly using the `title` parameter of the top-level page function.
|
||||
#'
|
||||
#'
|
||||
#' @examples
|
||||
#' ## Only run examples in interactive R sessions
|
||||
#' if (interactive()) {
|
||||
@@ -263,16 +269,23 @@ 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.
|
||||
#'
|
||||
#' @family layout functions
|
||||
#'
|
||||
#' @examples
|
||||
#' ## Only run examples in interactive R sessions
|
||||
@@ -337,6 +350,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
|
||||
@@ -346,7 +377,7 @@ sidebarLayout <- function(sidebarPanel,
|
||||
#' @param fluid `TRUE` to use fluid layout; `FALSE` to use fixed
|
||||
#' layout.
|
||||
#'
|
||||
#' @seealso [fluidPage()], [flowLayout()]
|
||||
#' @family layout functions
|
||||
#'
|
||||
#' @examples
|
||||
#' ## Only run examples in interactive R sessions
|
||||
@@ -384,7 +415,7 @@ verticalLayout <- function(..., fluid = TRUE) {
|
||||
#' @param cellArgs Any additional attributes that should be used for each cell
|
||||
#' of the layout.
|
||||
#'
|
||||
#' @seealso [verticalLayout()]
|
||||
#' @family layout functions
|
||||
#'
|
||||
#' @examples
|
||||
#' ## Only run examples in interactive R sessions
|
||||
@@ -440,6 +471,8 @@ inputPanel <- function(...) {
|
||||
#' @param cellArgs Any additional attributes that should be used for each cell
|
||||
#' of the layout.
|
||||
#'
|
||||
#' @family layout functions
|
||||
#'
|
||||
#' @examples
|
||||
#' ## Only run examples in interactive R sessions
|
||||
#' if (interactive()) {
|
||||
@@ -537,7 +570,7 @@ splitLayout <- function(..., cellWidths = NULL, cellArgs = list()) {
|
||||
#' @param flex Determines how space should be distributed to the cells. Can be a
|
||||
#' single value like `1` or `2` to evenly distribute the available
|
||||
#' space; or use a vector of numbers to specify the proportions. For example,
|
||||
#' `flex = c(2, 3)` would cause the space to be split 40\%/60\% between
|
||||
#' `flex = c(2, 3)` would cause the space to be split 40%/60% between
|
||||
#' two cells. NA values will cause the corresponding cell to be sized
|
||||
#' according to its contents (without growing or shrinking).
|
||||
#' @param width,height The total amount of width and height to use for the
|
||||
|
||||
189
R/bootstrap.R
189
R/bootstrap.R
@@ -60,7 +60,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")
|
||||
@@ -103,7 +103,7 @@ basicPage <- function(...) {
|
||||
#' *automatic* height; that is, they determine their own height based on
|
||||
#' the height of their contained elements. However,
|
||||
#' `fillPage(plotOutput("plot", height = "100%"))` will work because
|
||||
#' `fillPage` fixes the `<body>` height at 100\% of the window height.
|
||||
#' `fillPage` fixes the `<body>` height at 100% of the window height.
|
||||
#'
|
||||
#' Note that `fillPage(plotOutput("plot"))` will not cause the plot to fill
|
||||
#' the page. Like most Shiny output widgets, `plotOutput`'s default height
|
||||
@@ -130,6 +130,8 @@ basicPage <- function(...) {
|
||||
#' @param bootstrap If `TRUE`, load the Bootstrap CSS library.
|
||||
#' @param theme URL to alternative Bootstrap stylesheet.
|
||||
#'
|
||||
#' @family layout functions
|
||||
#'
|
||||
#' @examples
|
||||
#' fillPage(
|
||||
#' tags$style(type = "text/css",
|
||||
@@ -178,61 +180,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
|
||||
@@ -288,6 +235,8 @@ pageWithSidebar <- function(headerPanel,
|
||||
#' [updateNavbarPage()], [insertTab()],
|
||||
#' [showTab()]
|
||||
#'
|
||||
#' @family layout functions
|
||||
#'
|
||||
#' @examples
|
||||
#' navbarPage("App Title",
|
||||
#' tabPanel("Plot"),
|
||||
@@ -408,27 +357,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 +369,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 +464,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
|
||||
@@ -917,50 +793,43 @@ buildTabItem <- function(index, tabsetId, foundSelected, tabs = NULL,
|
||||
|
||||
#' Create a text output element
|
||||
#'
|
||||
#' Render a reactive output variable as text within an application page. The
|
||||
#' text will be included within an HTML `div` tag by default.
|
||||
#' Render a reactive output variable as text within an application page.
|
||||
#' `textOutput()` is usually paired with [renderText()] and puts regular text
|
||||
#' in `<div>` or `<span>`; `verbatimTextOutput()` is usually paired with
|
||||
#' [renderPrint()] and provudes fixed-width text in a `<pre>`.
|
||||
#'
|
||||
#' In both funtions, text is HTML-escaped prior to rendering.
|
||||
#'
|
||||
#' @param outputId output variable to read the value from
|
||||
#' @param container a function to generate an HTML element to contain the text
|
||||
#' @param inline use an inline (`span()`) or block container (`div()`)
|
||||
#' for the output
|
||||
#' @return A text output element that can be included in a panel
|
||||
#' @details Text is HTML-escaped prior to rendering. This element is often used
|
||||
#' to display [renderText] output variables.
|
||||
#' @examples
|
||||
#' h3(textOutput("caption"))
|
||||
#' @export
|
||||
textOutput <- function(outputId, container = if (inline) span else div, inline = FALSE) {
|
||||
container(id = outputId, class = "shiny-text-output")
|
||||
}
|
||||
|
||||
#' Create a verbatim text output element
|
||||
#'
|
||||
#' Render a reactive output variable as verbatim text within an
|
||||
#' application page. The text will be included within an HTML `pre` tag.
|
||||
#' @param outputId output variable to read the value from
|
||||
#' @param placeholder if the output is empty or `NULL`, should an empty
|
||||
#' rectangle be displayed to serve as a placeholder? (does not affect
|
||||
#' behavior when the the output in nonempty)
|
||||
#' @return A verbatim text output element that can be included in a panel
|
||||
#' @details Text is HTML-escaped prior to rendering. This element is often used
|
||||
#' with the [renderPrint] function to preserve fixed-width formatting
|
||||
#' of printed objects.
|
||||
#' @return A output element for use in UI.
|
||||
#' @examples
|
||||
#' ## Only run this example in interactive R sessions
|
||||
#' if (interactive()) {
|
||||
#' shinyApp(
|
||||
#' ui = basicPage(
|
||||
#' textInput("txt", "Enter the text to display below:"),
|
||||
#' verbatimTextOutput("default"),
|
||||
#' verbatimTextOutput("placeholder", placeholder = TRUE)
|
||||
#' textOutput("text"),
|
||||
#' verbatimTextOutput("verb")
|
||||
#' ),
|
||||
#' server = function(input, output) {
|
||||
#' output$default <- renderText({ input$txt })
|
||||
#' output$placeholder <- renderText({ input$txt })
|
||||
#' output$text <- renderText({ input$txt })
|
||||
#' output$verb <- renderText({ input$txt })
|
||||
#' }
|
||||
#' )
|
||||
#' }
|
||||
#' @export
|
||||
textOutput <- function(outputId, container = if (inline) span else div, inline = FALSE) {
|
||||
container(id = outputId, class = "shiny-text-output")
|
||||
}
|
||||
|
||||
#' @param placeholder if the output is empty or `NULL`, should an empty
|
||||
#' rectangle be displayed to serve as a placeholder? (does not affect
|
||||
#' behavior when the the output in nonempty)
|
||||
#' @export
|
||||
#' @rdname textOutput
|
||||
verbatimTextOutput <- function(outputId, placeholder = FALSE) {
|
||||
pre(id = outputId,
|
||||
class = paste(c("shiny-text-output", if (!placeholder) "noplaceholder"),
|
||||
|
||||
81
R/globals.R
81
R/globals.R
@@ -1,23 +1,78 @@
|
||||
# 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 pkg is loaded at some
|
||||
# point the future (or, potentially, but less commonly,
|
||||
# unloaded & reloaded)
|
||||
setHook(
|
||||
packageEvent(pkg, "onLoad"),
|
||||
function(...) {
|
||||
registerS3method(generic, class, fun, envir = asNamespace(pkg))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
register_upgrade_message <- function(pkg, version) {
|
||||
# Is an out-dated version of this package installed?
|
||||
needs_upgrade <- function() {
|
||||
if (system.file(package = pkg) == "")
|
||||
return(FALSE)
|
||||
if (utils::packageVersion(pkg) >= version)
|
||||
return(FALSE)
|
||||
TRUE
|
||||
}
|
||||
|
||||
msg <- sprintf(
|
||||
"This version of Shiny is designed to work with '%s' >= %s.
|
||||
Please upgrade via install.packages('%s').",
|
||||
pkg, version, pkg
|
||||
)
|
||||
|
||||
if (pkg %in% loadedNamespaces() && needs_upgrade()) {
|
||||
packageStartupMessage(msg)
|
||||
}
|
||||
|
||||
# Always register hook in case pkg is loaded at some
|
||||
# point the future (or, potentially, but less commonly,
|
||||
# unloaded & reloaded)
|
||||
setHook(
|
||||
packageEvent(pkg, "onLoad"),
|
||||
function(...) {
|
||||
if (needs_upgrade()) packageStartupMessage(msg)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
.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))
|
||||
}
|
||||
|
||||
.onAttach <- function(libname, pkgname) {
|
||||
# Check for htmlwidgets version, if installed. As of Shiny 0.12.0 and
|
||||
# htmlwidgets 0.4, both packages switched from RJSONIO to jsonlite. Because of
|
||||
# this change, Shiny 0.12.0 will work only with htmlwidgets >= 0.4, and vice
|
||||
# versa.
|
||||
if (system.file(package = "htmlwidgets") != "" &&
|
||||
utils::packageVersion("htmlwidgets") < "0.4") {
|
||||
packageStartupMessage(
|
||||
"This version of Shiny is designed to work with htmlwidgets >= 0.4. ",
|
||||
"Please upgrade your version of htmlwidgets."
|
||||
)
|
||||
}
|
||||
# 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")
|
||||
|
||||
# Shiny 1.4.0 bumps jQuery 1.x to 3.x, which caused a problem
|
||||
# with static-rendering of htmlwidgets, and htmlwidgets 1.5
|
||||
# includes a fix for this problem
|
||||
# https://github.com/rstudio/shiny/issues/2630
|
||||
register_upgrade_message("htmlwidgets", 1.5)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -37,6 +37,13 @@
|
||||
#' }
|
||||
#'
|
||||
#' @seealso [observeEvent()] and [eventReactive()]
|
||||
#'
|
||||
#' @section Server value:
|
||||
#' An integer of class `"shinyActionButtonValue"`. This class differs from
|
||||
#' ordinary integers in that a value of 0 is considered "falsy".
|
||||
#' This implies two things:
|
||||
#' * Event handlers (e.g., [observeEvent()], [eventReactive()]) won't execute on initial load.
|
||||
#' * Input validation (e.g., [req()], [need()]) will fail on initial load.
|
||||
#' @export
|
||||
actionButton <- function(inputId, label, icon = NULL, width = NULL, ...) {
|
||||
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
#' }
|
||||
#' shinyApp(ui, server)
|
||||
#' }
|
||||
#'
|
||||
#' @section Server value:
|
||||
#' `TRUE` if checked, `FALSE` otherwise.
|
||||
#'
|
||||
#' @export
|
||||
checkboxInput <- function(inputId, label, value = FALSE, width = NULL) {
|
||||
|
||||
|
||||
@@ -67,6 +67,9 @@
|
||||
#'
|
||||
#' shinyApp(ui, server)
|
||||
#' }
|
||||
#' @section Server value:
|
||||
#' Character vector of values corresponding to the boxes that are checked.
|
||||
#'
|
||||
#' @export
|
||||
checkboxGroupInput <- function(inputId, label, choices = NULL, selected = NULL,
|
||||
inline = FALSE, width = NULL, choiceNames = NULL, choiceValues = NULL) {
|
||||
|
||||
@@ -86,6 +86,10 @@
|
||||
#'
|
||||
#' shinyApp(ui, server = function(input, output) { })
|
||||
#' }
|
||||
#'
|
||||
#' @section Server value:
|
||||
#' A [Date] vector of length 1.
|
||||
#'
|
||||
#' @export
|
||||
dateInput <- function(inputId, label, value = NULL, min = NULL, max = NULL,
|
||||
format = "yyyy-mm-dd", startview = "month", weekstart = 0,
|
||||
|
||||
@@ -70,6 +70,10 @@
|
||||
#'
|
||||
#' shinyApp(ui, server = function(input, output) { })
|
||||
#' }
|
||||
#'
|
||||
#' @section Server value:
|
||||
#' A [Date] vector of length 2.
|
||||
#'
|
||||
#' @export
|
||||
dateRangeInput <- function(inputId, label, start = NULL, end = NULL,
|
||||
min = NULL, max = NULL, format = "yyyy-mm-dd", startview = "month",
|
||||
@@ -92,9 +96,9 @@ dateRangeInput <- function(inputId, label, start = NULL, end = NULL,
|
||||
|
||||
shinyInputLabel(inputId, label),
|
||||
# input-daterange class is needed for dropdown behavior
|
||||
div(class = "input-daterange input-group",
|
||||
div(class = "input-daterange input-group input-group-sm",
|
||||
tags$input(
|
||||
class = "input-sm form-control",
|
||||
class = "form-control",
|
||||
type = "text",
|
||||
`data-date-language` = language,
|
||||
`data-date-week-start` = weekstart,
|
||||
@@ -105,9 +109,14 @@ dateRangeInput <- function(inputId, label, start = NULL, end = NULL,
|
||||
`data-initial-date` = start,
|
||||
`data-date-autoclose` = if (autoclose) "true" else "false"
|
||||
),
|
||||
span(class = "input-group-addon", separator),
|
||||
# input-group-prepend and input-group-append are for bootstrap 4 forward compat
|
||||
span(class = "input-group-addon input-group-prepend input-group-append",
|
||||
span(class = "input-group-text",
|
||||
separator
|
||||
)
|
||||
),
|
||||
tags$input(
|
||||
class = "input-sm form-control",
|
||||
class = "form-control",
|
||||
type = "text",
|
||||
`data-date-language` = language,
|
||||
`data-date-week-start` = weekstart,
|
||||
|
||||
113
R/input-file.R
113
R/input-file.R
@@ -3,8 +3,60 @@
|
||||
#' Create a file upload control that can be used to upload one or more files.
|
||||
#'
|
||||
#' Whenever a file upload completes, the corresponding input variable is set
|
||||
#' to a dataframe. This dataframe contains one row for each selected file, and
|
||||
#' the following columns:
|
||||
#' to a dataframe. See the `Server value` section.
|
||||
#'
|
||||
#' @family input elements
|
||||
#'
|
||||
#' @inheritParams textInput
|
||||
#' @param multiple Whether the user should be allowed to select and upload
|
||||
#' multiple files at once. **Does not work on older browsers, including
|
||||
#' Internet Explorer 9 and earlier.**
|
||||
#' @param accept A character vector of "unique file type specifiers" which
|
||||
#' gives the browser a hint as to the type of file the server expects.
|
||||
#' Many browsers use this prevent the user from selecting an invalid file.
|
||||
#'
|
||||
#' A unique file type specifier can be:
|
||||
#' * A case insensitive extension like `.csv` or `.rds`.
|
||||
#' * A valid MIME type, like `text/plain` or `application/pdf`
|
||||
#' * One of `audio/*`, `video/*`, or `image/*` meaning any audio, video,
|
||||
#' or image type, respectively.
|
||||
#' @param buttonLabel The label used on the button. Can be text or an HTML tag
|
||||
#' object.
|
||||
#' @param placeholder The text to show before a file has been uploaded.
|
||||
#'
|
||||
#' @examples
|
||||
#' ## Only run examples in interactive R sessions
|
||||
#' if (interactive()) {
|
||||
#'
|
||||
#' ui <- fluidPage(
|
||||
#' sidebarLayout(
|
||||
#' sidebarPanel(
|
||||
#' fileInput("file1", "Choose CSV File", accept = ".csv"),
|
||||
#' checkboxInput("header", "Header", TRUE)
|
||||
#' ),
|
||||
#' mainPanel(
|
||||
#' tableOutput("contents")
|
||||
#' )
|
||||
#' )
|
||||
#' )
|
||||
#'
|
||||
#' server <- function(input, output) {
|
||||
#' output$contents <- renderTable({
|
||||
#' file <- input$file1
|
||||
#' ext <- tools::file_ext(file$datapath)
|
||||
#'
|
||||
#' req(file)
|
||||
#' validate(need(ext == "csv", "Please upload a csv file"))
|
||||
#'
|
||||
#' read.csv(file$datapath, header = input$header)
|
||||
#' })
|
||||
#' }
|
||||
#'
|
||||
#' shinyApp(ui, server)
|
||||
#' }
|
||||
#'
|
||||
#' @section Server value:
|
||||
#' A `data.frame` that contains one row for each selected file, and following columns:
|
||||
#' \describe{
|
||||
#' \item{`name`}{The filename provided by the web browser. This is
|
||||
#' **not** the path to read to get at the actual data that was uploaded
|
||||
@@ -19,58 +71,6 @@
|
||||
#' operation.}
|
||||
#' }
|
||||
#'
|
||||
#' @family input elements
|
||||
#'
|
||||
#' @inheritParams textInput
|
||||
#' @param multiple Whether the user should be allowed to select and upload
|
||||
#' multiple files at once. **Does not work on older browsers, including
|
||||
#' Internet Explorer 9 and earlier.**
|
||||
#' @param accept A character vector of MIME types; gives the browser a hint of
|
||||
#' what kind of files the server is expecting.
|
||||
#' @param buttonLabel The label used on the button. Can be text or an HTML tag
|
||||
#' object.
|
||||
#' @param placeholder The text to show before a file has been uploaded.
|
||||
#'
|
||||
#' @examples
|
||||
#' ## Only run examples in interactive R sessions
|
||||
#' if (interactive()) {
|
||||
#'
|
||||
#' ui <- fluidPage(
|
||||
#' sidebarLayout(
|
||||
#' sidebarPanel(
|
||||
#' fileInput("file1", "Choose CSV File",
|
||||
#' accept = c(
|
||||
#' "text/csv",
|
||||
#' "text/comma-separated-values,text/plain",
|
||||
#' ".csv")
|
||||
#' ),
|
||||
#' tags$hr(),
|
||||
#' checkboxInput("header", "Header", TRUE)
|
||||
#' ),
|
||||
#' mainPanel(
|
||||
#' tableOutput("contents")
|
||||
#' )
|
||||
#' )
|
||||
#' )
|
||||
#'
|
||||
#' server <- function(input, output) {
|
||||
#' output$contents <- renderTable({
|
||||
#' # input$file1 will be NULL initially. After the user selects
|
||||
#' # and uploads a file, it will be a data frame with 'name',
|
||||
#' # 'size', 'type', and 'datapath' columns. The 'datapath'
|
||||
#' # column will contain the local filenames where the data can
|
||||
#' # be found.
|
||||
#' inFile <- input$file1
|
||||
#'
|
||||
#' if (is.null(inFile))
|
||||
#' return(NULL)
|
||||
#'
|
||||
#' read.csv(inFile$datapath, header = input$header)
|
||||
#' })
|
||||
#' }
|
||||
#'
|
||||
#' shinyApp(ui, server)
|
||||
#' }
|
||||
#' @export
|
||||
fileInput <- function(inputId, label, multiple = FALSE, accept = NULL,
|
||||
width = NULL, buttonLabel = "Browse...", placeholder = "No file selected") {
|
||||
@@ -106,7 +106,8 @@ fileInput <- function(inputId, label, multiple = FALSE, accept = NULL,
|
||||
shinyInputLabel(inputId, label),
|
||||
|
||||
div(class = "input-group",
|
||||
tags$label(class = "input-group-btn",
|
||||
# input-group-prepend is for bootstrap 4 compat
|
||||
tags$label(class = "input-group-btn input-group-prepend",
|
||||
span(class = "btn btn-default btn-file",
|
||||
buttonLabel,
|
||||
inputTag
|
||||
@@ -119,7 +120,7 @@ fileInput <- function(inputId, label, multiple = FALSE, accept = NULL,
|
||||
|
||||
tags$div(
|
||||
id=paste(inputId, "_progress", sep=""),
|
||||
class="progress progress-striped active shiny-file-input-progress",
|
||||
class="progress active shiny-file-input-progress",
|
||||
tags$div(class="progress-bar")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
#' }
|
||||
#' shinyApp(ui, server)
|
||||
#' }
|
||||
#'
|
||||
#' @section Server value:
|
||||
#' A numeric vector of length 1.
|
||||
#'
|
||||
#' @export
|
||||
numericInput <- function(inputId, label, value, min = NA, max = NA, step = NA,
|
||||
width = NULL) {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
#' @family input elements
|
||||
#' @seealso [updateTextInput()]
|
||||
#'
|
||||
#' @section Server value:
|
||||
#' A character string of the password input. The default value is `""`
|
||||
#' unless `value` is provided.
|
||||
#'
|
||||
#' @examples
|
||||
#' ## Only run examples in interactive R sessions
|
||||
#' if (interactive()) {
|
||||
|
||||
@@ -80,6 +80,10 @@
|
||||
#'
|
||||
#' shinyApp(ui, server)
|
||||
#' }
|
||||
#'
|
||||
#' @section Server value:
|
||||
#' A character string containing the value of the selected button.
|
||||
#'
|
||||
#' @export
|
||||
radioButtons <- function(inputId, label, choices = NULL, selected = NULL,
|
||||
inline = FALSE, width = NULL, choiceNames = NULL, choiceValues = NULL) {
|
||||
|
||||
@@ -3,33 +3,32 @@
|
||||
#' Create a select list that can be used to choose a single or multiple items
|
||||
#' from a list of values.
|
||||
#'
|
||||
#' By default, `selectInput()` and `selectizeInput()` use the
|
||||
#' JavaScript library \pkg{selectize.js}
|
||||
#' (<https://github.com/selectize/selectize.js>) instead of the basic
|
||||
#' select input element. To use the standard HTML select input element, use
|
||||
#' `selectInput()` with `selectize=FALSE`.
|
||||
#' By default, `selectInput()` and `selectizeInput()` use the JavaScript library
|
||||
#' \pkg{selectize.js} (<https://github.com/selectize/selectize.js>) instead of
|
||||
#' the basic select input element. To use the standard HTML select input
|
||||
#' element, use `selectInput()` with `selectize=FALSE`.
|
||||
#'
|
||||
#' In selectize mode, if the first element in `choices` has a value of
|
||||
#' `""`, its name will be treated as a placeholder prompt. For example:
|
||||
#' In selectize mode, if the first element in `choices` has a value of `""`, its
|
||||
#' name will be treated as a placeholder prompt. For example:
|
||||
#' `selectInput("letter", "Letter", c("Choose one" = "", LETTERS))`
|
||||
#'
|
||||
#' @inheritParams textInput
|
||||
#' @param choices List of values to select from. If elements of the list are
|
||||
#' named, then that name --- rather than the value --- is displayed to the
|
||||
#' user. It's also possible to group related inputs by providing a named list
|
||||
#' whose elements are (either named or unnamed) lists, vectors, or factors. In this
|
||||
#' case, the outermost names will be used as the group labels (leveraging the
|
||||
#' `<optgroup>` HTML tag) for the elements in the respective sublist. See the
|
||||
#' example section for a small demo of this feature.
|
||||
#' @param selected The initially selected value (or multiple values if
|
||||
#' `multiple = TRUE`). If not specified then defaults to the first value
|
||||
#' for single-select lists and no values for multiple select lists.
|
||||
#' whose elements are (either named or unnamed) lists, vectors, or factors. In
|
||||
#' this case, the outermost names will be used as the group labels (leveraging
|
||||
#' the `<optgroup>` HTML tag) for the elements in the respective sublist. See
|
||||
#' the example section for a small demo of this feature.
|
||||
#' @param selected The initially selected value (or multiple values if `multiple
|
||||
#' = TRUE`). If not specified then defaults to the first value for
|
||||
#' single-select lists and no values for multiple select lists.
|
||||
#' @param multiple Is selection of multiple items allowed?
|
||||
#' @param selectize Whether to use \pkg{selectize.js} or not.
|
||||
#' @param size Number of items to show in the selection box; a larger number
|
||||
#' will result in a taller box. Not compatible with `selectize=TRUE`.
|
||||
#' Normally, when `multiple=FALSE`, a select input will be a drop-down
|
||||
#' list, but when `size` is set, it will be a box instead.
|
||||
#' Normally, when `multiple=FALSE`, a select input will be a drop-down list,
|
||||
#' but when `size` is set, it will be a box instead.
|
||||
#' @return A select list control that can be added to a UI definition.
|
||||
#'
|
||||
#' @family input elements
|
||||
@@ -72,6 +71,11 @@
|
||||
#' }
|
||||
#' )
|
||||
#' }
|
||||
#'
|
||||
#' @section Server value: A vector of character strings, usually of length
|
||||
#' 1, with the value of the selected items. When `multiple=TRUE` and
|
||||
#' nothing is selected, this value will be `NULL`.
|
||||
#'
|
||||
#' @export
|
||||
selectInput <- function(inputId, label, choices, selected = NULL,
|
||||
multiple = FALSE, selectize = TRUE, width = NULL,
|
||||
@@ -225,18 +229,6 @@ selectizeIt <- function(inputId, select, options, nonempty = FALSE) {
|
||||
#' Create a select list that can be used to choose a single or multiple items
|
||||
#' from the column names of a data frame.
|
||||
#'
|
||||
#' The resulting server `input` value will be returned as:
|
||||
#' \itemize{
|
||||
#' \item a symbol if `multiple = FALSE`. The `input` value should be
|
||||
#' used with rlang's [rlang::!!()]. For example,
|
||||
#' `ggplot2::aes(!!input$variable)`.
|
||||
#' \item a list of symbols if `multiple = TRUE`. The `input` value
|
||||
#' should be used with rlang's [rlang::!!!()] to expand
|
||||
#' the symbol list as individual arguments. For example,
|
||||
#' `dplyr::select(mtcars, !!!input$variabls)` which is
|
||||
#' equivalent to `dplyr::select(mtcars, !!input$variabls[[1]], !!input$variabls[[2]], ..., !!input$variabls[[length(input$variabls)]])`.
|
||||
#' }
|
||||
#'
|
||||
#' By default, `varSelectInput()` and `selectizeInput()` use the
|
||||
#' JavaScript library \pkg{selectize.js}
|
||||
#' (<https://github.com/selectize/selectize.js>) to instead of the basic
|
||||
@@ -249,6 +241,19 @@ selectizeIt <- function(inputId, select, options, nonempty = FALSE) {
|
||||
#'
|
||||
#' @family input elements
|
||||
#' @seealso [updateSelectInput()]
|
||||
#'
|
||||
#' @section Server value:
|
||||
#' The resulting server `input` value will be returned as:
|
||||
#'
|
||||
#' * A symbol if `multiple = FALSE`. The `input` value should be
|
||||
#' used with rlang's [rlang::!!()]. For example,
|
||||
#' `ggplot2::aes(!!input$variable)`.
|
||||
#' * A list of symbols if `multiple = TRUE`. The `input` value
|
||||
#' should be used with rlang's [rlang::!!!()] to expand
|
||||
#' the symbol list as individual arguments. For example,
|
||||
#' `dplyr::select(mtcars, !!!input$variabls)` which is
|
||||
#' equivalent to `dplyr::select(mtcars, !!input$variabls[[1]], !!input$variabls[[2]], ..., !!input$variabls[[length(input$variabls)]])`.
|
||||
#'
|
||||
#' @examples
|
||||
#'
|
||||
#' ## Only run examples in interactive R sessions
|
||||
|
||||
@@ -70,6 +70,10 @@
|
||||
#' # Complete app with UI and server components
|
||||
#' shinyApp(ui, server)
|
||||
#' }
|
||||
#'
|
||||
#' @section Server value:
|
||||
#' A number, or in the case of slider range, a vector of two numbers.
|
||||
#'
|
||||
#' @export
|
||||
sliderInput <- function(inputId, label, min, max, value, step = NULL,
|
||||
round = FALSE, format = NULL, locale = NULL,
|
||||
|
||||
@@ -28,6 +28,11 @@
|
||||
#' }
|
||||
#' shinyApp(ui, server)
|
||||
#' }
|
||||
#'
|
||||
#' @section Server value:
|
||||
#' A character string of the text input. The default value is `""`
|
||||
#' unless `value` is provided.
|
||||
#'
|
||||
#' @export
|
||||
textInput <- function(inputId, label, value = "", width = NULL,
|
||||
placeholder = NULL) {
|
||||
|
||||
@@ -35,6 +35,11 @@
|
||||
#' shinyApp(ui, server)
|
||||
#'
|
||||
#' }
|
||||
#'
|
||||
#' @section Server value:
|
||||
#' A character string of the text input. The default value is `""`
|
||||
#' unless `value` is provided.
|
||||
#'
|
||||
#' @export
|
||||
textAreaInput <- function(inputId, label, value = "", width = NULL, height = NULL,
|
||||
cols = NULL, rows = NULL, placeholder = NULL, resize = NULL) {
|
||||
|
||||
108
R/input-utils.R
108
R/input-utils.R
@@ -90,41 +90,83 @@ generateOptions <- function(inputId, selected, inline, type = 'checkbox',
|
||||
div(class = "shiny-options-group", options)
|
||||
}
|
||||
|
||||
# Take a vector or list, and convert to named list. Also, if any children are
|
||||
# vectors with length > 1, convert those to list. If the list is unnamed,
|
||||
# convert it to a named list with blank names.
|
||||
listify <- function(x) {
|
||||
if (is.list(x) || is.null(x)) {
|
||||
asNamedVector(lapply(x, listify))
|
||||
} else if (is.character(x)) {
|
||||
if (length(x) == 1 && is.null(names(x))) {
|
||||
x
|
||||
} else {
|
||||
as.list(asNamedVector(x))
|
||||
}
|
||||
} else {
|
||||
# Can get here if x is a factor.
|
||||
listify(stats::setNames(as.character(x), names(x)))
|
||||
}
|
||||
# True when a choice list item represents a group of related inputs.
|
||||
isGroup <- function(choice) {
|
||||
is.list(choice) ||
|
||||
!is.null(names(choice)) ||
|
||||
length(choice) > 1 ||
|
||||
length(choice) == 0
|
||||
}
|
||||
|
||||
# Takes a vector or list, and adds names (same as the value) to any entries
|
||||
# True when choices is a list and contains at least one group of related inputs.
|
||||
hasGroups <- function(choices) {
|
||||
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).
|
||||
setDefaultNames <- function(x) {
|
||||
x <- asNamed(x)
|
||||
emptyNames <- names(x) == ""
|
||||
names(x)[emptyNames] <- as.character(x)[emptyNames]
|
||||
x
|
||||
}
|
||||
|
||||
# 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) {
|
||||
# We assert choices is a list, since only a list may contain a group.
|
||||
stopifnot(is.list(choices))
|
||||
# The list might be unnamed by this point. We add default names of "" so that
|
||||
# names(choices) is not zero-length and mapply can work. Within mapply, we
|
||||
# error if any group's name is ""
|
||||
choices <- asNamed(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 (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), 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/list/factor, and adds names (same as the value) to any entries
|
||||
# without names. Coerces all leaf nodes to `character`.
|
||||
choicesWithNames <- function(choices) {
|
||||
|
||||
choices <- listify(choices)
|
||||
if (length(choices) == 0) return(choices)
|
||||
|
||||
# Recurse into any subgroups
|
||||
choices <- mapply(choices, names(choices), FUN = function(choice, name) {
|
||||
if (!is.list(choice)) return(choice)
|
||||
if (name == "") stop('All sub-lists in "choices" must be named.')
|
||||
choicesWithNames(choice)
|
||||
}, SIMPLIFY = FALSE)
|
||||
|
||||
# default missing names to choice values
|
||||
missing <- names(choices) == ""
|
||||
names(choices)[missing] <- as.character(choices)[missing]
|
||||
|
||||
choices
|
||||
if (hasGroups(choices)) {
|
||||
processGroupedChoices(choices)
|
||||
} else {
|
||||
processFlatChoices(choices)
|
||||
}
|
||||
}
|
||||
|
||||
160
R/insert-ui.R
160
R/insert-ui.R
@@ -1,55 +1,54 @@
|
||||
#' Insert UI objects
|
||||
#' Insert and remove UI objects
|
||||
#'
|
||||
#' Insert a UI object into the app.
|
||||
#'
|
||||
#' This function allows you to dynamically add an arbitrarily large UI
|
||||
#' object into your app, whenever you want, as many times as you want.
|
||||
#' Unlike [renderUI()], the UI generated with `insertUI`
|
||||
#' is not updatable as a whole: once it's created, it stays there. Each
|
||||
#' new call to `insertUI` creates more UI objects, in addition to
|
||||
#' These functions allow you to dynamically add and remove arbirary UI
|
||||
#' into your app, whenever you want, as many times as you want.
|
||||
#' Unlike [renderUI()], the UI generated with `insertUI()` is persistent:
|
||||
#' once it's created, it stays there until removed by `removeUI()`. Each
|
||||
#' new call to `insertUI()` creates more UI objects, in addition to
|
||||
#' the ones already there (all independent from one another). To
|
||||
#' update a part of the UI (ex: an input object), you must use the
|
||||
#' appropriate `render` function or a customized `reactive`
|
||||
#' function. To remove any part of your UI, use [removeUI()].
|
||||
#' function.
|
||||
#'
|
||||
#' @param selector A string that is accepted by jQuery's selector (i.e. the
|
||||
#' string `s` to be placed in a `$(s)` jQuery call). This selector
|
||||
#' will determine the element(s) relative to which you want to insert your
|
||||
#' UI object.
|
||||
#' It's particularly useful to pair `removeUI` with `insertUI()`, but there is
|
||||
#' no restriction on what you can use on. Any element that can be selected
|
||||
#' through a jQuery selector can be removed through this function.
|
||||
#'
|
||||
#' @param selector A string that is accepted by jQuery's selector
|
||||
#' (i.e. the string `s` to be placed in a `$(s)` jQuery call).
|
||||
#'
|
||||
#' For `insertUI()` this determines the element(s) relative to which you
|
||||
#' want to insert your UI object. For `removeUI()` this determine the
|
||||
#' element(s) to be removed. If you want to remove a Shiny input or output,
|
||||
#' note that many of these are wrapped in `<div>`s, so you may need to use a
|
||||
#' somewhat complex selector --- see the Examples below. (Alternatively, you
|
||||
#' could also wrap the inputs/outputs that you want to be able to remove
|
||||
#' easily in a `<div>` with an id.)
|
||||
#' @param where Where your UI object should go relative to the selector:
|
||||
#' \describe{
|
||||
#' \item{`beforeBegin`}{Before the selector element itself}
|
||||
#' \item{`afterBegin`}{Just inside the selector element, before its
|
||||
#' first child}
|
||||
#' \item{`beforeEnd`}{Just inside the selector element, after its
|
||||
#' last child (default)}
|
||||
#' \item{`afterEnd`}{After the selector element itself}
|
||||
#' }
|
||||
#' Adapted from
|
||||
#' [here](https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML).
|
||||
#'
|
||||
#' \describe{
|
||||
#' \item{`beforeBegin`}{Before the selector element itself}
|
||||
#' \item{`afterBegin`}{Just inside the selector element, before its
|
||||
#' first child}
|
||||
#' \item{`beforeEnd`}{Just inside the selector element, after its
|
||||
#' last child (default)}
|
||||
#' \item{`afterEnd`}{After the selector element itself}
|
||||
#' }
|
||||
#' Adapted from <https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML>.
|
||||
#' @param ui The UI object you want to insert. This can be anything that
|
||||
#' you usually put inside your apps's `ui` function. If you're inserting
|
||||
#' multiple elements in one call, make sure to wrap them in either a
|
||||
#' `tagList()` or a `tags$div()` (the latter option has the
|
||||
#' advantage that you can give it an `id` to make it easier to
|
||||
#' reference or remove it later on). If you want to insert raw html, use
|
||||
#' `ui = HTML()`.
|
||||
#'
|
||||
#' you usually put inside your apps's `ui` function. If you're inserting
|
||||
#' multiple elements in one call, make sure to wrap them in either a
|
||||
#' `tagList()` or a `tags$div()` (the latter option has the
|
||||
#' advantage that you can give it an `id` to make it easier to
|
||||
#' reference or remove it later on). If you want to insert raw html, use
|
||||
#' `ui = HTML()`.
|
||||
#' @param multiple In case your selector matches more than one element,
|
||||
#' `multiple` determines whether Shiny should insert the UI object
|
||||
#' relative to all matched elements or just relative to the first
|
||||
#' matched element (default).
|
||||
#'
|
||||
#' @param immediate Whether the UI object should be immediately inserted into
|
||||
#' the app when you call `insertUI`, or whether Shiny should wait until
|
||||
#' all outputs have been updated and all observers have been run (default).
|
||||
#'
|
||||
#' @param session The shiny session within which to call `insertUI`.
|
||||
#'
|
||||
#' @seealso [removeUI()]
|
||||
#'
|
||||
#' `multiple` determines whether Shiny should insert the UI object
|
||||
#' relative to all matched elements or just relative to the first
|
||||
#' matched element (default).
|
||||
#' @param immediate Whether the UI object should be immediately inserted
|
||||
#' or removed, or whether Shiny should wait until all outputs have been
|
||||
#' updated and all observers have been run (default).
|
||||
#' @param session The shiny session. Advanced use only.
|
||||
#' @examples
|
||||
#' ## Only run this example in interactive R sessions
|
||||
#' if (interactive()) {
|
||||
@@ -73,6 +72,26 @@
|
||||
#' # Complete app with UI and server components
|
||||
#' shinyApp(ui, server)
|
||||
#' }
|
||||
#'
|
||||
#' if (interactive()) {
|
||||
#' # Define UI
|
||||
#' ui <- fluidPage(
|
||||
#' actionButton("rmv", "Remove UI"),
|
||||
#' textInput("txt", "This is no longer useful")
|
||||
#' )
|
||||
#'
|
||||
#' # Server logic
|
||||
#' server <- function(input, output, session) {
|
||||
#' observeEvent(input$rmv, {
|
||||
#' removeUI(
|
||||
#' selector = "div:has(> #txt)"
|
||||
#' )
|
||||
#' })
|
||||
#' }
|
||||
#'
|
||||
#' # Complete app with UI and server components
|
||||
#' shinyApp(ui, server)
|
||||
#' }
|
||||
#' @export
|
||||
insertUI <- function(selector,
|
||||
where = c("beforeBegin", "afterBegin", "beforeEnd", "afterEnd"),
|
||||
@@ -100,60 +119,7 @@ insertUI <- function(selector,
|
||||
}
|
||||
|
||||
|
||||
#' Remove UI objects
|
||||
#'
|
||||
#' Remove a UI object from the app.
|
||||
#'
|
||||
#' This function allows you to remove any part of your UI. Once `removeUI`
|
||||
#' is executed on some element, it is gone forever.
|
||||
#'
|
||||
#' While it may be a particularly useful pattern to pair this with
|
||||
#' [insertUI()] (to remove some UI you had previously inserted),
|
||||
#' there is no restriction on what you can use `removeUI` on. Any
|
||||
#' element that can be selected through a jQuery selector can be removed
|
||||
#' through this function.
|
||||
#'
|
||||
#' @param selector A string that is accepted by jQuery's selector (i.e. the
|
||||
#' string `s` to be placed in a `$(s)` jQuery call). This selector
|
||||
#' will determine the element(s) to be removed. If you want to remove a
|
||||
#' Shiny input or output, note that many of these are wrapped in `div`s,
|
||||
#' so you may need to use a somewhat complex selector --- see the Examples below.
|
||||
#' (Alternatively, you could also wrap the inputs/outputs that you want to be
|
||||
#' able to remove easily in a `div` with an id.)
|
||||
#'
|
||||
#' @param multiple In case your selector matches more than one element,
|
||||
#' `multiple` determines whether Shiny should remove all the matched
|
||||
#' elements or just the first matched element (default).
|
||||
#'
|
||||
#' @param immediate Whether the element(s) should be immediately removed from
|
||||
#' the app when you call `removeUI`, or whether Shiny should wait until
|
||||
#' all outputs have been updated and all observers have been run (default).
|
||||
#'
|
||||
#' @param session The shiny session within which to call `removeUI`.
|
||||
#'
|
||||
#' @seealso [insertUI()]
|
||||
#'
|
||||
#' @examples
|
||||
#' ## Only run this example in interactive R sessions
|
||||
#' if (interactive()) {
|
||||
#' # Define UI
|
||||
#' ui <- fluidPage(
|
||||
#' actionButton("rmv", "Remove UI"),
|
||||
#' textInput("txt", "This is no longer useful")
|
||||
#' )
|
||||
#'
|
||||
#' # Server logic
|
||||
#' server <- function(input, output, session) {
|
||||
#' observeEvent(input$rmv, {
|
||||
#' removeUI(
|
||||
#' selector = "div:has(> #txt)"
|
||||
#' )
|
||||
#' })
|
||||
#' }
|
||||
#'
|
||||
#' # Complete app with UI and server components
|
||||
#' shinyApp(ui, server)
|
||||
#' }
|
||||
#' @rdname insertUI
|
||||
#' @export
|
||||
removeUI <- function(selector,
|
||||
multiple = FALSE,
|
||||
|
||||
@@ -3,7 +3,27 @@ NULL
|
||||
|
||||
reactLogHandler <- function(req) {
|
||||
if (! rLog$isLogging()) {
|
||||
return(NULL)
|
||||
if (
|
||||
identical(req$PATH_INFO, "/reactlog/mark") ||
|
||||
identical(req$PATH_INFO, "/reactlog")
|
||||
) {
|
||||
# is not logging, but is a reactlog path...
|
||||
|
||||
return(
|
||||
httpResponse(
|
||||
# Not Implemented
|
||||
# - The server either does not recognize the request method, or it lacks the ability to fulfil the request.
|
||||
status = 501,
|
||||
content_type = "text/plain; charset=utf-8",
|
||||
content = "To enable reactlog, set the following option before running the application: \n\noptions(shiny.reactlog = TRUE)"
|
||||
)
|
||||
)
|
||||
|
||||
} else {
|
||||
# continue on like normal
|
||||
return(NULL)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (identical(req$PATH_INFO, "/reactlog/mark")) {
|
||||
@@ -37,6 +57,7 @@ reactLogHandler <- function(req) {
|
||||
))
|
||||
|
||||
} else {
|
||||
# continue on like normal
|
||||
return(NULL)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
435
R/mock-session.R
Normal file
435
R/mock-session.R
Normal file
@@ -0,0 +1,435 @@
|
||||
# Promise helpers taken from:
|
||||
# https://github.com/rstudio/promises/blob/master/tests/testthat/common.R
|
||||
# Block until all pending later tasks have executed
|
||||
wait_for_it <- function() {
|
||||
while (!later::loop_empty()) {
|
||||
later::run_now(0.1)
|
||||
}
|
||||
}
|
||||
|
||||
# Block until the promise is resolved/rejected. If resolved, return the value.
|
||||
# If rejected, throw (yes throw, not return) the error.
|
||||
#' @importFrom promises %...!%
|
||||
#' @importFrom promises %...>%
|
||||
extract <- function(promise) {
|
||||
promise_value <- NULL
|
||||
error <- NULL
|
||||
promise %...>%
|
||||
(function(value) promise_value <<- value) %...!%
|
||||
(function(reason) error <<- reason)
|
||||
|
||||
wait_for_it()
|
||||
if (!is.null(error))
|
||||
stop(error)
|
||||
else
|
||||
promise_value
|
||||
}
|
||||
|
||||
# TODO: is there a way to get this behavior without exporting these functions? R6?
|
||||
# TODO: clientData is documented as a reactiveValues, which this is not. Is it possible that
|
||||
# users are currently assigning into clientData? That would not work as expected here.
|
||||
#' @noRd
|
||||
#' @export
|
||||
`$.mockclientdata` <- function(x, name) {
|
||||
if (name == "allowDataUriScheme") { return(TRUE) }
|
||||
if (name == "pixelratio") { return(1) }
|
||||
if (name == "url_protocol") { return("http:") }
|
||||
if (name == "url_hostname") { return("mocksession") }
|
||||
if (name == "url_port") { return(1234) }
|
||||
if (name == "url_pathname") { return("/mockpath") }
|
||||
if (name == "url_hash") { return("#mockhash") }
|
||||
if (name == "url_hash_initial") { return("#mockhash") }
|
||||
if (name == "url_search") { return("?mocksearch=1") }
|
||||
|
||||
clientRE <- "^output_(.+)_([^_]+)$"
|
||||
if(grepl(clientRE, name)) {
|
||||
# TODO: use proper regex group matching here instead of redundantly parsing
|
||||
el <- sub(clientRE, "\\1", name)
|
||||
att <- sub(clientRE, "\\2", name)
|
||||
|
||||
if (att == "width") {
|
||||
return(600)
|
||||
} else if (att == "height") {
|
||||
return(400)
|
||||
} else if (att == "hidden") {
|
||||
return(FALSE)
|
||||
}
|
||||
}
|
||||
warning("Unexpected clientdata attribute accessed: ", name)
|
||||
return(NULL)
|
||||
}
|
||||
|
||||
#' @noRd
|
||||
#' @export
|
||||
`[[.mockclientdata` <- `$.mockclientdata`
|
||||
|
||||
#' @noRd
|
||||
#' @export
|
||||
`[.mockclientdata` <- function(values, name) {
|
||||
stop("Single-bracket indexing of mockclientdata is not allowed.")
|
||||
}
|
||||
|
||||
#' Mock Shiny Session
|
||||
#'
|
||||
#' @description
|
||||
#' An R6 class suitable for testing that simulates the `session` parameter
|
||||
#' provided to Shiny server functions or modules.
|
||||
#'
|
||||
#' @include timer.R
|
||||
#' @export
|
||||
MockShinySession <- R6Class(
|
||||
'MockShinySession',
|
||||
portable = FALSE,
|
||||
public = list(
|
||||
#' @field env The environment associated with the session.
|
||||
env = NULL,
|
||||
#' @field singletons Hardcoded as empty. Needed for rendering HTML (i.e. renderUI)
|
||||
singletons = character(0),
|
||||
#' @field clientData Mock client data that always returns a size for plots
|
||||
clientData = structure(list(), class="mockclientdata"),
|
||||
#' @description No-op
|
||||
#' @param logEntry Not used
|
||||
reactlog = function(logEntry){},
|
||||
#' @description No-op
|
||||
incrementBusyCount = function(){},
|
||||
#' @field output The shinyoutputs associated with the session
|
||||
output = NULL,
|
||||
#' @field input The reactive inputs associated with the session
|
||||
input = NULL,
|
||||
#' @field userData An environment initialized as empty.
|
||||
userData = NULL,
|
||||
#' @field progressStack A stack of progress objects
|
||||
progressStack = 'Stack',
|
||||
|
||||
#' @description Create a new MockShinySession
|
||||
initialize = function() {
|
||||
private$.input <- ReactiveValues$new(dedupe = FALSE, label = "input")
|
||||
private$flushCBs <- Callbacks$new()
|
||||
private$flushedCBs <- Callbacks$new()
|
||||
private$endedCBs <- Callbacks$new()
|
||||
private$timer <- MockableTimerCallbacks$new()
|
||||
self$progressStack <- Stack$new()
|
||||
|
||||
self$userData <- new.env(parent=emptyenv())
|
||||
|
||||
# create output
|
||||
out <- .createOutputWriter(self)
|
||||
class(out) <- "shinyoutput"
|
||||
self$output <- out
|
||||
|
||||
# Create a read-only copy of the inputs reactive.
|
||||
self$input <- .createReactiveValues(private$.input, readonly = TRUE)
|
||||
},
|
||||
#' @description Define a callback to be invoked before a reactive flush
|
||||
#' @param fun The function to invoke
|
||||
#' @param once If `TRUE`, will only run once. Otherwise, will run every time reactives are flushed.
|
||||
onFlush = function(fun, once=TRUE) {
|
||||
if (!isTRUE(once)) {
|
||||
return(private$flushCBs$register(fun))
|
||||
} else {
|
||||
dereg <- private$flushCBs$register(function() {
|
||||
dereg()
|
||||
fun()
|
||||
})
|
||||
return(dereg)
|
||||
}
|
||||
},
|
||||
#' @description Define a callback to be invoked after a reactive flush
|
||||
#' @param fun The function to invoke
|
||||
#' @param once If `TRUE`, will only run once. Otherwise, will run every time reactives are flushed.
|
||||
onFlushed = function(fun, once=TRUE) {
|
||||
if (!isTRUE(once)) {
|
||||
return(private$flushedCBs$register(fun))
|
||||
} else {
|
||||
dereg <- private$flushedCBs$register(function() {
|
||||
dereg()
|
||||
fun()
|
||||
})
|
||||
return(dereg)
|
||||
}
|
||||
},
|
||||
#' @description Define a callback to be invoked when the session ends
|
||||
#' @param sessionEndedCallback The callback to invoke when the session has ended.
|
||||
onEnded = function(sessionEndedCallback) {
|
||||
private$endedCBs$register(sessionEndedCallback)
|
||||
},
|
||||
|
||||
#' @description Returns `FALSE` if the session has not yet been closed
|
||||
isEnded = function(){ private$closed },
|
||||
#' @description Returns `FALSE` if the session has not yet been closed
|
||||
isClosed = function(){ private$closed },
|
||||
#' @description Closes the session
|
||||
close = function(){ private$closed <- TRUE },
|
||||
|
||||
#FIXME: this is wrong. Will need to be more complex.
|
||||
#' @description Unsophisticated mock implementation that merely invokes
|
||||
#' the given callback immediately.
|
||||
#' @param callback The callback ato be invoked.
|
||||
cycleStartAction = function(callback){ callback() },
|
||||
|
||||
#' @description Base64-encode the given file. Needed for image rendering.
|
||||
#' @param name Not used
|
||||
#' @param file The file to be encoded
|
||||
#' @param contentType The content type of the base64-encoded string
|
||||
fileUrl = function(name, file, contentType='application/octet-stream') {
|
||||
bytes <- file.info(file)$size
|
||||
if (is.na(bytes))
|
||||
return(NULL)
|
||||
|
||||
fileData <- readBin(file, 'raw', n=bytes)
|
||||
b64 <- rawToBase64(fileData)
|
||||
return(paste('data:', contentType, ';base64,', b64, sep=''))
|
||||
},
|
||||
|
||||
#' @description Sets reactive values associated with the `session$inputs` object
|
||||
#' and flushes the reactives.
|
||||
#' @param ... The inputs to set.
|
||||
#' @examples
|
||||
#' s <- MockShinySession$new()
|
||||
#' s$setInputs(x=1, y=2)
|
||||
setInputs = function(...) {
|
||||
vals <- list(...)
|
||||
mapply(names(vals), vals, FUN = function(name, value) {
|
||||
private$.input$set(name, value)
|
||||
})
|
||||
private$flush()
|
||||
},
|
||||
|
||||
#' @description An internal method which shouldn't be used by others.
|
||||
#' @param millis The number of milliseconds on which to schedule a callback
|
||||
#' @param callback The function to schedule
|
||||
.scheduleTask = function(millis, callback) {
|
||||
id <- private$timer$schedule(millis, callback)
|
||||
|
||||
# Return a deregistration callback
|
||||
function() {
|
||||
invisible(private$timer$unschedule(id))
|
||||
}
|
||||
},
|
||||
|
||||
#' @description Simulate the passing of time by the given number of milliseconds.
|
||||
#' @param millis The number of milliseconds to advance time.
|
||||
elapse = function(millis) {
|
||||
msLeft <- millis
|
||||
|
||||
while (msLeft > 0){
|
||||
t <- private$timer$timeToNextEvent()
|
||||
|
||||
if (is.infinite(t) || t <= 0 || msLeft < t){
|
||||
# Either there's no good upcoming event or we can't make it to it in the allotted time.
|
||||
break
|
||||
}
|
||||
msLeft <- msLeft - t
|
||||
private$timer$elapse(t)
|
||||
|
||||
# timerCallbacks must run before flushReact.
|
||||
private$timer$executeElapsed()
|
||||
private$flush()
|
||||
}
|
||||
|
||||
private$timer$elapse(msLeft)
|
||||
|
||||
# Run again in case our callbacks resulted in a scheduled
|
||||
# function that needs executing.
|
||||
private$timer$executeElapsed()
|
||||
private$flush()
|
||||
},
|
||||
|
||||
#' @description An internal method which shouldn't be used by others.
|
||||
.now = function() {
|
||||
# Returns elapsed time in milliseconds
|
||||
private$timer$getElapsed()
|
||||
},
|
||||
|
||||
#' @description An internal method which shouldn't be used by others.
|
||||
#' @param name The name of the output
|
||||
#' @param func The render definition
|
||||
#' @param label Not used
|
||||
defineOutput = function(name, func, label) {
|
||||
force(name)
|
||||
|
||||
if (!is.null(private$outs[[name]]$obs)) {
|
||||
private$outs[[name]]$obs$destroy()
|
||||
}
|
||||
|
||||
if (is.null(func)) func <- missingOutput
|
||||
|
||||
if (!is.function(func))
|
||||
stop(paste("Unexpected", class(func), "output for", name))
|
||||
|
||||
obs <- observe({
|
||||
# We could just stash the promise, but we get an "unhandled promise error". This bypasses
|
||||
prom <- NULL
|
||||
tryCatch({
|
||||
v <- func(self, name)
|
||||
if (!promises::is.promise(v)){
|
||||
# Make our sync value into a promise
|
||||
prom <- promises::promise(function(resolve, reject){ resolve(v) })
|
||||
} else {
|
||||
prom <- v
|
||||
}
|
||||
}, error=function(e){
|
||||
# Error running value()
|
||||
prom <<- promises::promise(function(resolve, reject){ reject(e) })
|
||||
})
|
||||
|
||||
private$outs[[name]]$promise <- hybrid_chain(
|
||||
prom,
|
||||
function(v){
|
||||
list(val = v, err = NULL)
|
||||
}, catch=function(e){
|
||||
list(val = NULL, err = e)
|
||||
})
|
||||
})
|
||||
private$outs[[name]] <- list(obs = obs, func = func, promise = NULL)
|
||||
},
|
||||
|
||||
#' @description An internal method which shouldn't be used by others.
|
||||
#' @param name The name of the output
|
||||
getOutput = function(name) {
|
||||
# Unlike the real outputs, we're going to return the last value rather than the unevaluated function
|
||||
if (is.null(private$outs[[name]])) {
|
||||
stop("The test referenced an output that hasn't been defined yet: output$", name)
|
||||
}
|
||||
|
||||
if (is.null(private$outs[[name]]$promise)) {
|
||||
# Means the output was defined but the observer hasn't had a chance to run
|
||||
# yet. Run flushReact() now to force the observer to run.
|
||||
flushReact()
|
||||
|
||||
if (is.null(private$outs[[name]]$promise)) {
|
||||
stop("output$", name, " encountered an unexpected error resolving its promise")
|
||||
}
|
||||
}
|
||||
|
||||
# Make promise return
|
||||
v <- extract(private$outs[[name]]$promise)
|
||||
if (!is.null(v$err)){
|
||||
stop(v$err)
|
||||
} else {
|
||||
v$val
|
||||
}
|
||||
},
|
||||
|
||||
#' @description No-op
|
||||
#' @param name Not used
|
||||
#' @param data Not used
|
||||
#' @param filterFunc Not used
|
||||
registerDataObj = function(name, data, filterFunc) {},
|
||||
#' @description No-op
|
||||
#' @param value Not used
|
||||
allowReconnect = function(value) {},
|
||||
#' @description No-op
|
||||
reload = function() {},
|
||||
#' @description No-op
|
||||
#' @param brushId Not used
|
||||
resetBrush = function(brushId) {
|
||||
warning("session$brush isn't meaningfully mocked on the MockShinySession")
|
||||
},
|
||||
#' @description No-op
|
||||
#' @param type Not used
|
||||
#' @param message Not used
|
||||
sendCustomMessage = function(type, message) {},
|
||||
#' @description No-op
|
||||
#' @param type Not used
|
||||
#' @param message Not used
|
||||
sendBinaryMessage = function(type, message) {},
|
||||
#' @description No-op
|
||||
#' @param inputId Not used
|
||||
#' @param message Not used
|
||||
sendInputMessage = function(inputId, message) {},
|
||||
#' @description No-op
|
||||
#' @param names Not used
|
||||
setBookmarkExclude = function(names) {
|
||||
warning("Bookmarking isn't meaningfully mocked in MockShinySession")
|
||||
},
|
||||
#' @description No-op
|
||||
getBookmarkExclude = function() {
|
||||
warning("Bookmarking isn't meaningfully mocked in MockShinySession")
|
||||
},
|
||||
#' @description No-op
|
||||
#' @param fun Not used
|
||||
onBookmark = function(fun) {},
|
||||
#' @description No-op
|
||||
#' @param fun Not used
|
||||
onBookmarked = function(fun) {},
|
||||
#' @description No-op
|
||||
doBookmark = function() {
|
||||
warning("Bookmarking isn't meaningfully mocked in MockShinySession")
|
||||
},
|
||||
#' @description No-op
|
||||
#' @param fun Not used
|
||||
onRestore = function(fun) {},
|
||||
#' @description No-op
|
||||
#' @param fun Not used
|
||||
onRestored = function(fun) {},
|
||||
#' @description No-op
|
||||
exportTestValues = function() {},
|
||||
#' @description No-op
|
||||
#' @param input Not used
|
||||
#' @param output Not used
|
||||
#' @param export Not used
|
||||
#' @param format Not used
|
||||
getTestSnapshotUrl = function(input=TRUE, output=TRUE, export=TRUE, format="json") {},
|
||||
#' @description Returns the given id prefixed by `mock-session-`.
|
||||
#' @param id The id to modify.
|
||||
ns = function(id) {
|
||||
paste0("mock-session-", id) # TODO: does this need to be more complex/intelligent?
|
||||
},
|
||||
#' @description Trigger a reactive flush right now.
|
||||
flushReact = function(){
|
||||
private$flush()
|
||||
},
|
||||
#' @description Create and return a namespace-specific session proxy.
|
||||
#' @param namespace Character vector indicating a namespace.
|
||||
makeScope = function(namespace) {
|
||||
ns <- NS(namespace)
|
||||
createSessionProxy(
|
||||
self,
|
||||
input = .createReactiveValues(private$.input, readonly = TRUE, ns = ns),
|
||||
output = structure(.createOutputWriter(self, ns = ns), class = "shinyoutput"),
|
||||
makeScope = function(namespace) self$makeScope(ns(namespace))
|
||||
)
|
||||
}
|
||||
),
|
||||
private = list(
|
||||
.input = NULL,
|
||||
flushCBs = NULL,
|
||||
flushedCBs = NULL,
|
||||
endedCBs = NULL,
|
||||
timer = NULL,
|
||||
closed = FALSE,
|
||||
outs = list(),
|
||||
returnedVal = NULL,
|
||||
|
||||
flush = function(){
|
||||
isolate(private$flushCBs$invoke(..stacktraceon = TRUE))
|
||||
shiny:::flushReact() # namespace to avoid calling our own method
|
||||
isolate(private$flushedCBs$invoke(..stacktraceon = TRUE))
|
||||
later::run_now()
|
||||
}
|
||||
),
|
||||
active = list(
|
||||
# If assigning to `returned`, proactively flush
|
||||
#' @field returned The value returned from the module
|
||||
returned = function(value){
|
||||
if(missing(value)){
|
||||
return(private$returnedVal)
|
||||
}
|
||||
# When you assign to returned, that implies that you just ran
|
||||
# the module. So we should proactively flush. We have to do this
|
||||
# here since flush is private.
|
||||
private$returnedVal <- value
|
||||
private$flush()
|
||||
},
|
||||
#' @field request An empty environment where the request should be. The request isn't meaningfully mocked currently.
|
||||
request = function(value) {
|
||||
if (!missing(value)){
|
||||
stop("session$request can't be assigned to")
|
||||
}
|
||||
warning("session$request doesn't currently simulate a realistic request on MockShinySession")
|
||||
new.env(parent=emptyenv())
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
90
R/modules.R
90
R/modules.R
@@ -37,24 +37,104 @@ createSessionProxy <- function(parentSession, ...) {
|
||||
`[[<-.session_proxy` <- `$<-.session_proxy`
|
||||
|
||||
|
||||
#' Invoke a Shiny module
|
||||
#' Shiny modules
|
||||
#'
|
||||
#' Shiny's module feature lets you break complicated UI and server logic into
|
||||
#' smaller, self-contained pieces. Compared to large monolithic Shiny apps,
|
||||
#' modules are easier to reuse and easier to reason about. See the article at
|
||||
#' <http://shiny.rstudio.com/articles/modules.html> to learn more.
|
||||
#'
|
||||
#' @param module A Shiny module server function
|
||||
#' Starting in Shiny 1.5.0, we recommend using `moduleFunction` instead of
|
||||
#' `callModule`, because syntax is a little easier to understand.
|
||||
#'
|
||||
#' @param module A Shiny module server function.
|
||||
#' @param id An ID string that corresponds with the ID used to call the module's
|
||||
#' UI function
|
||||
#' @param ... Additional parameters to pass to module server function
|
||||
#' UI function.
|
||||
#' @param ... For `callModule`, additional parameters to pass to module server
|
||||
#' function.
|
||||
#' @param session Session from which to make a child scope (the default should
|
||||
#' almost always be used)
|
||||
#' almost always be used).
|
||||
#'
|
||||
#' @return The return value, if any, from executing the module server function
|
||||
#' @seealso <http://shiny.rstudio.com/articles/modules.html>
|
||||
#'
|
||||
#' @examples
|
||||
#' # Define the UI for a module
|
||||
#' counterUI <- function(id, label = "Counter") {
|
||||
#' ns <- NS(id)
|
||||
#' tagList(
|
||||
#' actionButton(ns("button"), label = label),
|
||||
#' verbatimTextOutput(ns("out"))
|
||||
#' )
|
||||
#' }
|
||||
#'
|
||||
#' # Define the server logic for a module
|
||||
#' counterServer <- function(id) {
|
||||
#' moduleServer(id, function(input, output, session) {
|
||||
#' count <- reactiveVal(0)
|
||||
#' observeEvent(input$button, {
|
||||
#' count(count() + 1)
|
||||
#' })
|
||||
#' output$out <- renderText({
|
||||
#' count()
|
||||
#' })
|
||||
#' count
|
||||
#' })
|
||||
#' }
|
||||
#'
|
||||
#' # Use the module in an app
|
||||
#' ui <- fluidPage(
|
||||
#' counterUI("counter1", "Counter #1"),
|
||||
#' counterUI("counter2", "Counter #2")
|
||||
#' )
|
||||
#' server <- function(input, output, session) {
|
||||
#' counterServer("counter1")
|
||||
#' counterServer("counter2")
|
||||
#' }
|
||||
#' if (interactive()) {
|
||||
#' shinyApp(ui, server)
|
||||
#' }
|
||||
#'
|
||||
#'
|
||||
#'
|
||||
#' # If you want to pass extra parameters to the module's server logic, you can
|
||||
#' # add them to your function. In this case `prefix` is text that will be
|
||||
#' # printed before the count.
|
||||
#' counterServer2 <- function(id, prefix = NULL) {
|
||||
#' moduleServer(id, function(input, output, session) {
|
||||
#' count <- reactiveVal(0)
|
||||
#' observeEvent(input$button, {
|
||||
#' count(count() + 1)
|
||||
#' })
|
||||
#' output$out <- renderText({
|
||||
#' paste0(prefix, count())
|
||||
#' })
|
||||
#' count
|
||||
#' })
|
||||
#' }
|
||||
#'
|
||||
#' ui <- fluidPage(
|
||||
#' counterUI("counter", "Counter"),
|
||||
#' )
|
||||
#' server <- function(input, output, session) {
|
||||
#' counterServer2("counter", "The current count is: ")
|
||||
#' }
|
||||
#' if (interactive()) {
|
||||
#' shinyApp(ui, server)
|
||||
#' }
|
||||
#'
|
||||
#' @export
|
||||
moduleServer <- function(id, module, session = getDefaultReactiveDomain()) {
|
||||
callModule(module, id, session = session)
|
||||
}
|
||||
|
||||
|
||||
#' @rdname moduleServer
|
||||
#' @export
|
||||
callModule <- function(module, id, ..., session = getDefaultReactiveDomain()) {
|
||||
if (!inherits(session, c("ShinySession", "session_proxy", "MockShinySession"))) {
|
||||
stop("session must be a ShinySession or session_proxy object.")
|
||||
}
|
||||
childScope <- session$makeScope(id)
|
||||
|
||||
withReactiveDomain(childScope, {
|
||||
|
||||
@@ -12,11 +12,13 @@
|
||||
#' disappear.
|
||||
#' @param closeButton If `TRUE`, display a button which will make the
|
||||
#' notification disappear when clicked. If `FALSE` do not display.
|
||||
#' @param id An ID string. This can be used to change the contents of an
|
||||
#' existing message with `showNotification`, or to remove it with
|
||||
#' `removeNotification`. If not provided, one will be generated
|
||||
#' automatically. If an ID is provided and there does not currently exist a
|
||||
#' notification with that ID, a new notification will be created with that ID.
|
||||
#' @param id A unique identifier for the notification.
|
||||
#'
|
||||
#' `id` is optional for `showNotification()`: Shiny will automatically create
|
||||
#' one if needed. If you do supply it, Shiny will update an existing
|
||||
#' notification if it exists, otherwise it will create a new one.
|
||||
#'
|
||||
#' `id` is required for `removeNotification()`.
|
||||
#' @param type A string which controls the color of the notification. One of
|
||||
#' "default" (gray), "message" (blue), "warning" (yellow), or "error" (red).
|
||||
#' @param session Session object to send notification to.
|
||||
@@ -97,10 +99,8 @@ showNotification <- function(ui, action = NULL, duration = 5,
|
||||
|
||||
#' @rdname showNotification
|
||||
#' @export
|
||||
removeNotification <- function(id = NULL, session = getDefaultReactiveDomain()) {
|
||||
if (is.null(id)) {
|
||||
stop("id is required.")
|
||||
}
|
||||
removeNotification <- function(id, session = getDefaultReactiveDomain()) {
|
||||
force(id)
|
||||
session$sendNotification("remove", id)
|
||||
id
|
||||
}
|
||||
|
||||
74
R/progress.R
74
R/progress.R
@@ -20,50 +20,12 @@
|
||||
#' [`shinyOptions(progress.style="old")`][shinyOptions] just once, inside the server
|
||||
#' function.
|
||||
#'
|
||||
#' **Methods**
|
||||
#' \describe{
|
||||
#' \item{`initialize(session, min = 0, max = 1)`}{
|
||||
#' Creates a new progress panel (but does not display it).
|
||||
#' }
|
||||
#' \item{`set(value = NULL, message = NULL, detail = NULL)`}{
|
||||
#' Updates the progress panel. When called the first time, the
|
||||
#' progress panel is displayed.
|
||||
#' }
|
||||
#' \item{`inc(amount = 0.1, message = NULL, detail = NULL)`}{
|
||||
#' Like `set`, this updates the progress panel. The difference is
|
||||
#' that `inc` increases the progress bar by `amount`, instead
|
||||
#' of setting it to a specific value.
|
||||
#' }
|
||||
#' \item{`close()`}{
|
||||
#' Removes the progress panel. Future calls to `set` and
|
||||
#' `close` will be ignored.
|
||||
#' }
|
||||
#' }
|
||||
#'
|
||||
#' @param session The Shiny session object, as provided by
|
||||
#' `shinyServer` to the server function.
|
||||
#' @param min The value that represents the starting point of the
|
||||
#' progress bar. Must be less than `max`.
|
||||
#' @param max The value that represents the end of the progress bar.
|
||||
#' Must be greater than `min`.
|
||||
#' @param message A single-element character vector; the message to be
|
||||
#' displayed to the user, or `NULL` to hide the current message
|
||||
#' (if any).
|
||||
#' @param detail A single-element character vector; the detail message
|
||||
#' to be displayed to the user, or `NULL` to hide the current
|
||||
#' detail message (if any). The detail message will be shown with a
|
||||
#' de-emphasized appearance relative to `message`.
|
||||
#' @param value A numeric value at which to set
|
||||
#' the progress bar, relative to `min` and `max`.
|
||||
#' @param style Progress display style. If `"notification"` (the default),
|
||||
#' the progress indicator will show using Shiny's notification API. If
|
||||
#' `"old"`, use the same HTML and CSS used in Shiny 0.13.2 and below
|
||||
#' (this is for backward-compatibility).
|
||||
#' @param amount Single-element numeric vector; the value at which to set
|
||||
#' the progress bar, relative to `min` and `max`.
|
||||
#' `NULL` hides the progress bar, if it is currently visible.
|
||||
#' @param amount For the `inc()` method, a numeric value to increment the
|
||||
#' progress bar.
|
||||
#' displayed to the user, or `NULL` to hide the current message (if any).
|
||||
#' @param detail A single-element character vector; the detail message to be
|
||||
#' displayed to the user, or `NULL` to hide the current detail message (if
|
||||
#' any). The detail message will be shown with a de-emphasized appearance
|
||||
#' relative to `message`.
|
||||
#'
|
||||
#' @examples
|
||||
#' ## Only run examples in interactive R sessions
|
||||
@@ -99,6 +61,17 @@ Progress <- R6Class(
|
||||
'Progress',
|
||||
public = list(
|
||||
|
||||
#' @description Creates a new progress panel (but does not display it).
|
||||
#' @param session The Shiny session object, as provided by `shinyServer` to
|
||||
#' the server function.
|
||||
#' @param min The value that represents the starting point of the progress
|
||||
#' bar. Must be less than `max`.
|
||||
#' @param max The value that represents the end of the progress bar. Must be
|
||||
#' greater than `min`.
|
||||
#' @param style Progress display style. If `"notification"` (the default),
|
||||
#' the progress indicator will show using Shiny's notification API. If
|
||||
#' `"old"`, use the same HTML and CSS used in Shiny 0.13.2 and below (this
|
||||
#' is for backward-compatibility).
|
||||
initialize = function(session = getDefaultReactiveDomain(),
|
||||
min = 0, max = 1,
|
||||
style = getShinyOption("progress.style", default = "notification"))
|
||||
@@ -117,6 +90,11 @@ Progress <- R6Class(
|
||||
session$sendProgress('open', list(id = private$id, style = private$style))
|
||||
},
|
||||
|
||||
#' @description Updates the progress panel. When called the first time, the
|
||||
#' progress panel is displayed.
|
||||
#' @param value Single-element numeric vector; the value at which to set the
|
||||
#' progress bar, relative to `min` and `max`. `NULL` hides the progress
|
||||
#' bar, if it is currently visible.
|
||||
set = function(value = NULL, message = NULL, detail = NULL) {
|
||||
if (private$closed) {
|
||||
warning("Attempting to set progress, but progress already closed.")
|
||||
@@ -143,6 +121,11 @@ Progress <- R6Class(
|
||||
private$session$sendProgress('update', data)
|
||||
},
|
||||
|
||||
#' @description Like `set`, this updates the progress panel. The difference
|
||||
#' is that `inc` increases the progress bar by `amount`, instead of
|
||||
#' setting it to a specific value.
|
||||
#' @param amount For the `inc()` method, a numeric value to increment the
|
||||
#' progress bar.
|
||||
inc = function(amount = 0.1, message = NULL, detail = NULL) {
|
||||
if (is.null(private$value))
|
||||
private$value <- private$min
|
||||
@@ -151,12 +134,17 @@ Progress <- R6Class(
|
||||
self$set(value, message, detail)
|
||||
},
|
||||
|
||||
#' @description Returns the minimum value.
|
||||
getMin = function() private$min,
|
||||
|
||||
#' @description Returns the maximum value.
|
||||
getMax = function() private$max,
|
||||
|
||||
#' @description Returns the current value.
|
||||
getValue = function() private$value,
|
||||
|
||||
#' @description Removes the progress panel. Future calls to `set` and
|
||||
#' `close` will be ignored.
|
||||
close = function() {
|
||||
if (private$closed) {
|
||||
warning("Attempting to close progress, but progress already closed.")
|
||||
|
||||
@@ -222,7 +222,7 @@ reactiveVal <- function(value = NULL, label = NULL) {
|
||||
rv$set(x)
|
||||
}
|
||||
},
|
||||
class = c("reactiveVal", "reactive"),
|
||||
class = c("reactiveVal", "reactive", "function"),
|
||||
label = label,
|
||||
.impl = rv
|
||||
)
|
||||
@@ -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
|
||||
@@ -961,7 +969,7 @@ reactive <- function(x, env = parent.frame(), quoted = FALSE, label = NULL,
|
||||
if (length(srcref) >= 2) attr(label, "srcref") <- srcref[[2]]
|
||||
attr(label, "srcfile") <- srcFileOfRef(srcref[[1]])
|
||||
o <- Observable$new(fun, label, domain, ..stacktraceon = ..stacktraceon)
|
||||
structure(o$getValue, observable = o, class = c("reactiveExpr", "reactive"))
|
||||
structure(o$getValue, observable = o, class = c("reactiveExpr", "reactive", "function"))
|
||||
}
|
||||
|
||||
# Given the srcref to a reactive expression, attempts to figure out what the
|
||||
@@ -1505,14 +1513,16 @@ reactiveTimer <- function(intervalMs=1000, session = getDefaultReactiveDomain())
|
||||
# reactId <- nextGlobalReactId()
|
||||
# rLog$define(reactId, paste0("timer(", intervalMs, ")"))
|
||||
|
||||
scheduler <- defineScheduler(session)
|
||||
|
||||
dependents <- Map$new()
|
||||
timerHandle <- scheduleTask(intervalMs, function() {
|
||||
timerHandle <- scheduler(intervalMs, function() {
|
||||
# Quit if the session is closed
|
||||
if (!is.null(session) && session$isClosed()) {
|
||||
return(invisible())
|
||||
}
|
||||
|
||||
timerHandle <<- scheduleTask(intervalMs, sys.function())
|
||||
timerHandle <<- scheduler(intervalMs, sys.function())
|
||||
|
||||
doInvalidate <- function() {
|
||||
lapply(
|
||||
@@ -1605,18 +1615,23 @@ reactiveTimer <- function(intervalMs=1000, session = getDefaultReactiveDomain())
|
||||
#' }
|
||||
#' @export
|
||||
invalidateLater <- function(millis, session = getDefaultReactiveDomain()) {
|
||||
|
||||
force(session)
|
||||
|
||||
ctx <- getCurrentContext()
|
||||
rLog$invalidateLater(ctx$.reactId, ctx$id, millis, session)
|
||||
|
||||
timerHandle <- scheduleTask(millis, function() {
|
||||
clear_on_ended_callback <- function() {}
|
||||
|
||||
scheduler <- defineScheduler(session)
|
||||
|
||||
timerHandle <- scheduler(millis, function() {
|
||||
if (is.null(session)) {
|
||||
ctx$invalidate()
|
||||
return(invisible())
|
||||
}
|
||||
|
||||
clear_on_ended_callback()
|
||||
|
||||
if (!session$isClosed()) {
|
||||
session$cycleStartAction(function() {
|
||||
ctx$invalidate()
|
||||
@@ -1627,7 +1642,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 +1736,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 +1760,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)
|
||||
}
|
||||
|
||||
@@ -2322,20 +2362,24 @@ debounce <- function(r, millis, priority = 100, domain = getDefaultReactiveDomai
|
||||
when = NULL # the deadline for the timer to fire; NULL if not scheduled
|
||||
)
|
||||
|
||||
# Responsible for tracking when f() changes.
|
||||
# Responsible for tracking when r() changes.
|
||||
firstRun <- TRUE
|
||||
observe({
|
||||
r()
|
||||
|
||||
if (firstRun) {
|
||||
# During the first run we don't want to set v$when, as this will kick off
|
||||
# the timer. We only want to do that when we see r() change.
|
||||
firstRun <<- FALSE
|
||||
|
||||
# Ensure r() is called only after setting firstRun to FALSE since r()
|
||||
# may throw an error
|
||||
r()
|
||||
return()
|
||||
}
|
||||
# This ensures r() is still tracked after firstRun
|
||||
r()
|
||||
|
||||
# The value (or possibly millis) changed. Start or reset the timer.
|
||||
v$when <- Sys.time() + millis()/1000
|
||||
v$when <- getDomainTimeMs(domain) + millis()
|
||||
}, label = "debounce tracker", domain = domain, priority = priority)
|
||||
|
||||
# This observer is the timer. It rests until v$when elapses, then touches
|
||||
@@ -2344,13 +2388,13 @@ debounce <- function(r, millis, priority = 100, domain = getDefaultReactiveDomai
|
||||
if (is.null(v$when))
|
||||
return()
|
||||
|
||||
now <- Sys.time()
|
||||
now <- getDomainTimeMs(domain)
|
||||
if (now >= v$when) {
|
||||
# Mod by 999999999 to get predictable overflow behavior
|
||||
v$trigger <- isolate(v$trigger %OR% 0) %% 999999999 + 1
|
||||
v$when <- NULL
|
||||
} else {
|
||||
invalidateLater((v$when - now) * 1000)
|
||||
invalidateLater(v$when - now)
|
||||
}
|
||||
}, label = "debounce timer", domain = domain, priority = priority)
|
||||
|
||||
@@ -2395,12 +2439,12 @@ throttle <- function(r, millis, priority = 100, domain = getDefaultReactiveDomai
|
||||
if (is.null(v$lastTriggeredAt)) {
|
||||
0
|
||||
} else {
|
||||
max(0, (v$lastTriggeredAt + millis()/1000) - Sys.time()) * 1000
|
||||
max(0, v$lastTriggeredAt + millis() - getDomainTimeMs(domain))
|
||||
}
|
||||
}
|
||||
|
||||
trigger <- function() {
|
||||
v$lastTriggeredAt <- Sys.time()
|
||||
v$lastTriggeredAt <- getDomainTimeMs(domain)
|
||||
# Mod by 999999999 to get predictable overflow behavior
|
||||
v$trigger <- isolate(v$trigger) %% 999999999 + 1
|
||||
v$pending <- FALSE
|
||||
|
||||
@@ -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.
|
||||
@@ -885,6 +889,14 @@ find_panel_info_non_api <- function(b, ggplot_format) {
|
||||
})
|
||||
}
|
||||
|
||||
# Use public API for getting the unit's type (grid::unitType(), added in R 4.0)
|
||||
# https://github.com/wch/r-source/blob/f9b8a42/src/library/grid/R/unit.R#L179
|
||||
getUnitType <- function(u) {
|
||||
tryCatch(
|
||||
get("unitType", envir = asNamespace("grid"))(u),
|
||||
error = function(e) attr(u, "unit", exact = TRUE)
|
||||
)
|
||||
}
|
||||
|
||||
# Given a gtable object, return the x and y ranges (in pixel dimensions)
|
||||
find_panel_ranges <- function(g, res) {
|
||||
@@ -900,11 +912,11 @@ find_panel_ranges <- function(g, res) {
|
||||
if (inherits(x, "unit.list")) {
|
||||
# For ggplot2 <= 1.0.1
|
||||
vapply(x, FUN.VALUE = logical(1), function(u) {
|
||||
isTRUE(attr(u, "unit", exact = TRUE) == "null")
|
||||
isTRUE(getUnitType(u) == "null")
|
||||
})
|
||||
} else {
|
||||
# For later versions of ggplot2
|
||||
attr(x, "unit", exact = TRUE) == "null"
|
||||
getUnitType(x) == "null"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -944,7 +956,11 @@ find_panel_ranges <- function(g, res) {
|
||||
|
||||
# The plotting panels all are 'null' units.
|
||||
null_sizes <- rep(NA_real_, length(rel_sizes))
|
||||
null_sizes[null_idx] <- as.numeric(rel_sizes[null_idx])
|
||||
# Workaround for `[.unit` forbidding zero-length subsets
|
||||
# https://github.com/wch/r-source/blob/f9b8a42/src/library/grid/R/unit.R#L448-L450
|
||||
if (length(null_idx)) {
|
||||
null_sizes[null_idx] <- as.numeric(rel_sizes[null_idx])
|
||||
}
|
||||
|
||||
# Total size allocated for panels is the total image size minus absolute
|
||||
# (non-panel) elements.
|
||||
|
||||
129
R/server.R
129
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)
|
||||
}
|
||||
})
|
||||
)
|
||||
@@ -1119,5 +1230,5 @@ inShinyServer <- function() {
|
||||
# This check was moved out of the main function body because of an issue with
|
||||
# the RStudio debugger. (#1474)
|
||||
isEmptyMessage <- function(msg) {
|
||||
identical(charToRaw("\003\xe9"), msg)
|
||||
identical(as.raw(c(0x03, 0xe9)), msg)
|
||||
}
|
||||
|
||||
@@ -16,20 +16,103 @@ 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 (defaults to `FALSE`)}{If `TRUE` when a Shiny app is launched, the
|
||||
#' app directory will be continually monitored for changes to files that
|
||||
#' have the extensions: r, htm, html, js, css, png, jpg, jpeg, gif. If any
|
||||
#' changes are detected, all connected Shiny sessions are reloaded. This
|
||||
#' allows for fast feedback loops when tweaking Shiny UI.
|
||||
#'
|
||||
#' Since monitoring for changes is expensive (we simply poll for last
|
||||
#' modified times), this feature is intended only for development.
|
||||
#'
|
||||
#' You can customize the file patterns Shiny will monitor by setting the
|
||||
#' shiny.autoreload.pattern option. For example, to monitor only ui.R:
|
||||
#' `options(shiny.autoreload.pattern = glob2rx("ui.R"))`
|
||||
#'
|
||||
#' The default polling interval is 500 milliseconds. You can change this
|
||||
#' by setting e.g. `options(shiny.autoreload.interval = 2000)` (every
|
||||
#' two seconds).}
|
||||
#' \item{shiny.deprecation.messages (defaults to `TRUE`)}{This controls whether messages for
|
||||
#' deprecated functions in Shiny will be printed. See
|
||||
#' [shinyDeprecated()] for more information.}
|
||||
#' \item{shiny.error (defaults to `NULL`)}{This can be a function which is called when an error
|
||||
#' occurs. For example, `options(shiny.error=recover)` will result a
|
||||
#' the debugger prompt when an error occurs.}
|
||||
#' \item{shiny.fullstacktrace (defaults to `FALSE`)}{Controls whether "pretty" (`FALSE`) or full
|
||||
#' stack traces (`TRUE`) are dumped to the console when errors occur during Shiny app execution.
|
||||
#' Pretty stack traces attempt to only show user-supplied code, but this pruning can't always
|
||||
#' be done 100% correctly.}
|
||||
#' \item{shiny.host (defaults to `"127.0.0.1"`)}{The IP address that Shiny should listen on. See
|
||||
#' [runApp()] for more information.}
|
||||
#' \item{shiny.jquery.version (defaults to `3`)}{The major version of jQuery to use.
|
||||
#' Currently only values of `3` or `1` are supported. If `1`, then jQuery 1.12.4 is used. If `3`,
|
||||
#' then jQuery 3.4.1 is used.}
|
||||
#' \item{shiny.json.digits (defaults to `16`)}{The number of digits to use when converting
|
||||
#' numbers to JSON format to send to the client web browser.}
|
||||
#' \item{shiny.launch.browser (defaults to `interactive()`)}{A boolean which controls the default behavior
|
||||
#' when an app is run. See [runApp()] for more information.}
|
||||
#' \item{shiny.maxRequestSize (defaults to 5MB)}{This is a number which specifies the maximum
|
||||
#' web request size, which serves as a size limit for file uploads.}
|
||||
#' \item{shiny.minified (defaults to `TRUE`)}{By default
|
||||
#' Whether or not to include Shiny's JavaScript as a minified (`shiny.min.js`)
|
||||
#' or un-minified (`shiny.js`) file. The un-minified version is larger,
|
||||
#' but can be helpful for development and debugging.}
|
||||
#' \item{shiny.port (defaults to a random open port)}{A port number that Shiny will listen on. See
|
||||
#' [runApp()] for more information.}
|
||||
#' \item{shiny.reactlog (defaults to `FALSE`)}{If `TRUE`, enable logging of reactive events,
|
||||
#' which can be viewed later with the [reactlogShow()] function.
|
||||
#' This incurs a substantial performance penalty and should not be used in
|
||||
#' production.}
|
||||
#' \item{shiny.sanitize.errors (defaults to `FALSE`)}{If `TRUE`, then normal errors (i.e.
|
||||
#' errors not wrapped in `safeError`) won't show up in the app; a simple
|
||||
#' generic error message is printed instead (the error and strack trace printed
|
||||
#' to the console remain unchanged). If you want to sanitize errors in general, but you DO want a
|
||||
#' particular error `e` to get displayed to the user, then set this option
|
||||
#' to `TRUE` and use `stop(safeError(e))` for errors you want the
|
||||
#' user to see.}
|
||||
#' \item{shiny.stacktraceoffset (defaults to `TRUE`)}{If `TRUE`, then Shiny's printed stack
|
||||
#' traces will display srcrefs one line above their usual location. This is
|
||||
#' an arguably more intuitive arrangement for casual R users, as the name
|
||||
#' of a function appears next to the srcref where it is defined, rather than
|
||||
#' where it is currently being called from.}
|
||||
#' \item{shiny.suppressMissingContextError (defaults to `FALSE`)}{Normally, invoking a reactive
|
||||
#' outside of a reactive context (or [isolate()]) results in
|
||||
#' an error. If this is `TRUE`, don't error in these cases. This
|
||||
#' should only be used for debugging or demonstrations of reactivity at the
|
||||
#' console.}
|
||||
#' \item{shiny.testmode (defaults to `FALSE`)}{If `TRUE`, then various features for testing Shiny
|
||||
#' applications are enabled.}
|
||||
#' \item{shiny.trace (defaults to `FALSE`)}{Print messages sent between the R server and the web
|
||||
#' browser client to the R console. This is useful for debugging. Possible
|
||||
#' values are `"send"` (only print messages sent to the client),
|
||||
#' `"recv"` (only print messages received by the server), `TRUE`
|
||||
#' (print all messages), or `FALSE` (default; don't print any of these
|
||||
#' messages).}
|
||||
#' \item{shiny.usecairo (defaults to `TRUE`)}{This is used to disable graphical rendering by the
|
||||
#' Cairo package, if it is installed. See [plotPNG()] for more
|
||||
#' information.}
|
||||
#' }
|
||||
#' @param ... Options to set, with the form `name = value`.
|
||||
#' @aliases shiny-options
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' shinyOptions(myOption = 10)
|
||||
|
||||
114
R/shiny.R
114
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(
|
||||
@@ -639,7 +554,7 @@ ShinySession <- R6Class(
|
||||
# that the resulting object is represented as an object in JSON
|
||||
# instead of an array, and so that the RDS data structure is of a
|
||||
# consistent type.
|
||||
values <- lapply(values, asNamedVector)
|
||||
values <- lapply(values, asNamed)
|
||||
|
||||
if (length(values) == 0) {
|
||||
return(httpResponse(400, "text/plain",
|
||||
@@ -808,6 +723,12 @@ ShinySession <- R6Class(
|
||||
requestFlush = function() {
|
||||
appsNeedingFlush$set(self$token, self)
|
||||
},
|
||||
.scheduleTask = function(millis, callback) {
|
||||
scheduleTask(millis, callback)
|
||||
},
|
||||
.now = function(){
|
||||
getTimeMs()
|
||||
},
|
||||
rootScope = function() {
|
||||
self
|
||||
},
|
||||
@@ -1041,7 +962,9 @@ ShinySession <- R6Class(
|
||||
output$suspend()
|
||||
}
|
||||
# ..stacktraceon matches with the top-level ..stacktraceoff..
|
||||
private$closedCallbacks$invoke(onError = printError, ..stacktraceon = TRUE)
|
||||
withReactiveDomain(self, {
|
||||
private$closedCallbacks$invoke(onError = printError, ..stacktraceon = TRUE)
|
||||
})
|
||||
},
|
||||
isClosed = function() {
|
||||
return(self$closed)
|
||||
@@ -1376,6 +1299,9 @@ ShinySession <- R6Class(
|
||||
|
||||
getCurrentOutputInfo = function() {
|
||||
name <- private$currentOutputName
|
||||
if (is.null(name)) {
|
||||
return(NULL)
|
||||
}
|
||||
|
||||
tmp_info <- private$outputInfo[[name]] %OR% list(name = name)
|
||||
|
||||
@@ -1629,8 +1555,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)
|
||||
@@ -2169,6 +2101,10 @@ outputOptions <- function(x, name, ...) {
|
||||
|
||||
#' Get information about the output that is currently being executed.
|
||||
#'
|
||||
#' @return A list with information about the current output, including the
|
||||
#' `name` of the output. If no output is currently being executed, this will
|
||||
#' return `NULL`.
|
||||
#'
|
||||
#' @param session The current Shiny session.
|
||||
#'
|
||||
#' @export
|
||||
|
||||
21
R/shinyui.R
21
R/shinyui.R
@@ -42,9 +42,28 @@ renderPage <- function(ui, connection, showcase=0, testMode=FALSE) {
|
||||
)
|
||||
}
|
||||
|
||||
jquery <- function() {
|
||||
version <- getOption("shiny.jquery.version", 3)
|
||||
if (version == 3) {
|
||||
return(htmlDependency(
|
||||
"jquery", "3.4.1",
|
||||
c(href = "shared"),
|
||||
script = "jquery.min.js"
|
||||
))
|
||||
}
|
||||
if (version == 1) {
|
||||
return(htmlDependency(
|
||||
"jquery", "1.12.4",
|
||||
c(href = "shared/legacy"),
|
||||
script = "jquery.min.js"
|
||||
))
|
||||
}
|
||||
stop("Unsupported version of jQuery: ", version)
|
||||
}
|
||||
|
||||
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"),
|
||||
jquery(),
|
||||
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
|
||||
|
||||
169
R/test-module.R
Normal file
169
R/test-module.R
Normal file
@@ -0,0 +1,169 @@
|
||||
|
||||
|
||||
#' Integration testing for Shiny modules or server functions
|
||||
#'
|
||||
#' Offer a way to test the reactive interactions in Shiny --- either in Shiny
|
||||
#' modules or in the server portion of a Shiny application. For more
|
||||
#' information, visit [the Shiny Dev Center article on integration
|
||||
#' testing](https://shiny.rstudio.com/articles/integration-testing.html).
|
||||
#' @param module The module to test
|
||||
#' @param expr Test code containing expectations. The test expression will run
|
||||
#' in the module's environment, meaning that the module's parameters (e.g.
|
||||
#' `input`, `output`, and `session`) will be available along with any other
|
||||
#' values created inside of the module.
|
||||
#' @param ... Additional arguments to pass to the module function. These
|
||||
#' arguments are processed with [rlang::list2()] and so are
|
||||
#' _[dynamic][rlang::dyn-dots]_.
|
||||
#' @return The result of evaluating `expr`.
|
||||
#' @include mock-session.R
|
||||
#' @rdname testModule
|
||||
#' @examples
|
||||
#' module <- function(input, output, session, multiplier = 2, prefix = "I am ") {
|
||||
#' myreactive <- reactive({
|
||||
#' input$x * multiplier
|
||||
#' })
|
||||
#' output$txt <- renderText({
|
||||
#' paste0(prefix, myreactive())
|
||||
#' })
|
||||
#' }
|
||||
#'
|
||||
#' # Basic Usage
|
||||
#' # -----------
|
||||
#' testModule(module, {
|
||||
#' session$setInputs(x = 1)
|
||||
#' # You're also free to use third-party
|
||||
#' # testing packages like testthat:
|
||||
#' # expect_equal(myreactive(), 2)
|
||||
#' stopifnot(myreactive() == 2)
|
||||
#' stopifnot(output$txt == "I am 2")
|
||||
#'
|
||||
#' session$setInputs(x = 2)
|
||||
#' stopifnot(myreactive() == 4)
|
||||
#' stopifnot(output$txt == "I am 4")
|
||||
#' # Any additional arguments, below, are passed along to the module.
|
||||
#' }, multiplier = 2)
|
||||
#'
|
||||
#' # Advanced Usage
|
||||
#' # --------------
|
||||
#' multiplier_arg_name = "multiplier"
|
||||
#' more_args <- list(prefix = "I am ")
|
||||
#' testModule(module, {
|
||||
#' session$setInputs(x = 1)
|
||||
#' stopifnot(myreactive() == 2)
|
||||
#' stopifnot(output$txt == "I am 2")
|
||||
#' # !!/:= and !!! from rlang are used below to splice computed arguments
|
||||
#' # into the testModule() argument list.
|
||||
#' }, !!multiplier_arg_name := 2, !!!more_args)
|
||||
#' @export
|
||||
testModule <- function(module, expr, ...) {
|
||||
.testModule(
|
||||
module,
|
||||
quosure = rlang::enquo(expr),
|
||||
dots = rlang::list2(...),
|
||||
env = rlang::caller_env()
|
||||
)
|
||||
}
|
||||
|
||||
#' @noRd
|
||||
#' @importFrom withr with_options
|
||||
.testModule <- function(module, quosure, dots, env) {
|
||||
# Modify the module function locally by inserting `session$env <-
|
||||
# environment()` at the beginning of its body. The dynamic environment of the
|
||||
# module function is saved so that it may be referenced after the module
|
||||
# function has returned. The saved dynamic environment is the basis for the
|
||||
# `data` argument of tidy_eval() when used below to evaluate `quosure`, the
|
||||
# test code expression.
|
||||
body(module) <- rlang::expr({
|
||||
session$env <- base::environment()
|
||||
!!!body(module)
|
||||
})
|
||||
|
||||
session <- MockShinySession$new()
|
||||
on.exit(if (!session$isClosed()) session$close())
|
||||
args <- append(dots, list(input = session$input, output = session$output, session = session))
|
||||
|
||||
isolate(
|
||||
withReactiveDomain(
|
||||
session,
|
||||
withr::with_options(list(`shiny.allowoutputreads`=TRUE), {
|
||||
# Assigning to `$returned` causes a flush to happen automatically.
|
||||
session$returned <- do.call(module, args)
|
||||
})
|
||||
)
|
||||
)
|
||||
|
||||
# Evaluate `quosure` in a reactive context, and in the provided `env`, but
|
||||
# with `env` masked by a shallow view of `session$env`, the environment that
|
||||
# was saved when the module function was invoked. flush is not needed before
|
||||
# entering the loop because the first expr executed is `{`.
|
||||
isolate({
|
||||
withReactiveDomain(
|
||||
session,
|
||||
withr::with_options(list(`shiny.allowoutputreads`=TRUE), {
|
||||
rlang::eval_tidy(
|
||||
quosure,
|
||||
data = rlang::as_data_mask(as.list(session$env)),
|
||||
env = env
|
||||
)
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
#' Test an app's server-side logic
|
||||
#' @param appDir The directory root of the Shiny application. If `NULL`, this function
|
||||
#' will work up the directory hierarchy --- starting with the current directory ---
|
||||
#' looking for a directory that contains an `app.R` or `server.R` file.
|
||||
#' @rdname testModule
|
||||
#' @export
|
||||
testServer <- function(expr, appDir=NULL) {
|
||||
if (is.null(appDir)){
|
||||
appDir <- findApp()
|
||||
}
|
||||
|
||||
app <- shinyAppDir(appDir)
|
||||
message("Testing application found in: ", appDir)
|
||||
server <- app$serverFuncSource()
|
||||
|
||||
origwd <- getwd()
|
||||
setwd(appDir)
|
||||
on.exit({ setwd(origwd) }, add=TRUE)
|
||||
|
||||
# Add `session` argument if not present
|
||||
fn_formals <- formals(server)
|
||||
if (! "session" %in% names(fn_formals)) {
|
||||
fn_formals$session <- bquote()
|
||||
formals(server) <- fn_formals
|
||||
}
|
||||
|
||||
# Test the server function almost as if it were a module. `dots` is empty
|
||||
# because server functions never take additional arguments.
|
||||
.testModule(
|
||||
server,
|
||||
quosure = rlang::enquo(expr),
|
||||
dots = list(),
|
||||
env = rlang::caller_env()
|
||||
)
|
||||
}
|
||||
|
||||
findApp <- function(startDir="."){
|
||||
dir <- normalizePath(startDir)
|
||||
|
||||
# The loop will either return or stop() itself.
|
||||
while (TRUE){
|
||||
if(file.exists.ci(file.path(dir, "app.R")) || file.exists.ci(file.path(dir, "server.R"))){
|
||||
return(dir)
|
||||
}
|
||||
|
||||
# Move up a directory
|
||||
origDir <- dir
|
||||
dir <- dirname(dir)
|
||||
|
||||
# Testing for "root" path can be tricky. OSs differ and on Windows, network shares
|
||||
# might have a \\ prefix. Easier to just see if we got stuck and abort.
|
||||
if (dir == origDir){
|
||||
# We can go no further.
|
||||
stop("No shiny app was found in ", startDir, " or any of its parent directories")
|
||||
}
|
||||
}
|
||||
}
|
||||
107
R/test.R
Normal file
107
R/test.R
Normal file
@@ -0,0 +1,107 @@
|
||||
|
||||
#' Check to see if the given text is a shinytest
|
||||
#' Scans for the magic string of `app <- ShinyDriver$new(` as an indicator that this is a shinytest.
|
||||
#' Brought in from shinytest to avoid having to export this function.
|
||||
#' @noRd
|
||||
isShinyTest <- function(text){
|
||||
lines <- grepl("app\\s*<-\\s*ShinyDriver\\$new\\(", text, perl=TRUE)
|
||||
any(lines)
|
||||
}
|
||||
|
||||
#' Runs the tests associated with this Shiny app
|
||||
#'
|
||||
#' Sources the `.R` files in the top-level of `tests/` much like `R CMD check`.
|
||||
#' These files are typically simple runners for tests nested in other
|
||||
#' directories under `tests/`.
|
||||
#'
|
||||
#' @param appDir The base directory for the application.
|
||||
#' @param filter If not `NULL`, only tests with file names matching this regular
|
||||
#' expression will be executed. Matching is performed on the file name
|
||||
#' including the extension.
|
||||
#'
|
||||
#' @details Historically, [shinytest](https://rstudio.github.io/shinytest/)
|
||||
#' recommended placing tests at the top-level of the `tests/` directory. In
|
||||
#' order to support that model, `testApp` first checks to see if the `.R`
|
||||
#' files in the `tests/` directory are all shinytests; if so, just calls out
|
||||
#' to [shinytest::testApp()].
|
||||
#' @export
|
||||
runTests <- function(appDir=".", filter=NULL){
|
||||
require(shiny)
|
||||
|
||||
testsDir <- file.path(appDir, "tests")
|
||||
if (!dirExists(testsDir)){
|
||||
stop("No tests directory found: ", testsDir)
|
||||
}
|
||||
runners <- list.files(testsDir, pattern="\\.r$", ignore.case = TRUE)
|
||||
|
||||
if (length(runners) == 0){
|
||||
message("No test runners found in ", testsDir)
|
||||
return(structure(list(result=NA, files=list()), class="shinytestrun"))
|
||||
}
|
||||
|
||||
if (!is.null(filter)){
|
||||
runners <- runners[grepl(filter, runners)]
|
||||
}
|
||||
if (length(runners) == 0){
|
||||
stop("No test runners matched the given filter: '", filter, "'")
|
||||
}
|
||||
|
||||
# Inspect each runner to see if it appears to be a shinytest
|
||||
isST <- vapply(runners, function(r){
|
||||
text <- readLines(file.path(testsDir, r), warn = FALSE)
|
||||
isShinyTest(text)
|
||||
}, logical(1))
|
||||
|
||||
if (all(isST)){
|
||||
# just call out to shinytest
|
||||
# We don't need to message/warn here since shinytest already does it.
|
||||
if (!requireNamespace("shinytest", quietly=TRUE) ){
|
||||
stop("It appears that the .R files in ", testsDir,
|
||||
" are all shinytests, but shinytest is not installed.")
|
||||
}
|
||||
|
||||
if (!getOption("shiny.autoload.r", TRUE)) {
|
||||
warning("You've disabled `shiny.autoload.r` via an option but this is not passed through to shinytest. Consider using a _disable_autoload.R file as described at https://rstd.io/shiny-autoload")
|
||||
}
|
||||
|
||||
sares <- shinytest::testApp(appDir)
|
||||
res <- list()
|
||||
lapply(sares$results, function(r){
|
||||
e <- NA_character_
|
||||
if (!r$pass){
|
||||
e <- simpleError("Unknown shinytest error")
|
||||
}
|
||||
res[[r$name]] <<- e
|
||||
})
|
||||
return(structure(list(result=all(is.na(res)), files=res), class="shinytestrun"))
|
||||
}
|
||||
|
||||
testenv <- new.env(parent=globalenv())
|
||||
renv <- new.env(parent=testenv)
|
||||
if (getOption("shiny.autoload.r", TRUE)) {
|
||||
loadSupport(appDir, renv=renv, globalrenv=testenv)
|
||||
} else if (file.exists.ci(file.path(appDir, "server.R"))){
|
||||
# then check for global.R to load
|
||||
if (file.exists(file.path.ci(appDir, "global.R"))){
|
||||
sourceUTF8(file.path.ci(appDir, "global.R"))
|
||||
}
|
||||
}
|
||||
|
||||
oldwd <- getwd()
|
||||
on.exit({
|
||||
setwd(oldwd)
|
||||
}, add=TRUE)
|
||||
|
||||
setwd(testsDir)
|
||||
|
||||
# Otherwise source all the runners -- each in their own environment.
|
||||
fileResults <- list()
|
||||
lapply(runners, function(r){
|
||||
env <- new.env(parent=renv)
|
||||
tryCatch({sourceUTF8(r, envir=env); fileResults[[r]] <<- NA_character_}, error=function(e){
|
||||
fileResults[[r]] <<- e
|
||||
})
|
||||
})
|
||||
|
||||
return(structure(list(result=all(is.na(fileResults)), files=fileResults), class="shinytestrun"))
|
||||
}
|
||||
67
R/timer.R
67
R/timer.R
@@ -1,6 +1,5 @@
|
||||
# Return the current time, in milliseconds from epoch, with
|
||||
# unspecified time zone.
|
||||
now <- function() {
|
||||
# Return the current time, in milliseconds from epoch.
|
||||
getTimeMs <- function() {
|
||||
as.numeric(Sys.time()) * 1000
|
||||
}
|
||||
|
||||
@@ -12,9 +11,11 @@ TimerCallbacks <- R6Class(
|
||||
.nextId = 0L,
|
||||
.funcs = 'Map',
|
||||
.times = data.frame(),
|
||||
.now = 'Function',
|
||||
|
||||
initialize = function() {
|
||||
initialize = function(nowFn = getTimeMs) {
|
||||
.funcs <<- Map$new()
|
||||
.now <<- nowFn
|
||||
},
|
||||
clear = function() {
|
||||
.nextId <<- 0L
|
||||
@@ -30,7 +31,7 @@ TimerCallbacks <- R6Class(
|
||||
id <- .nextId
|
||||
.nextId <<- .nextId + 1L
|
||||
|
||||
t <- now()
|
||||
t <- .now()
|
||||
|
||||
# TODO: Horribly inefficient, use a heap instead
|
||||
.times <<- rbind(.times, data.frame(time=t+millis,
|
||||
@@ -56,17 +57,17 @@ TimerCallbacks <- R6Class(
|
||||
timeToNextEvent = function() {
|
||||
if (dim(.times)[1] == 0)
|
||||
return(Inf)
|
||||
return(.times[1, 'time'] - now())
|
||||
return(.times[1, 'time'] - .now())
|
||||
},
|
||||
takeElapsed = function() {
|
||||
t <- now()
|
||||
elapsed <- .times$time < now()
|
||||
t <- .now()
|
||||
elapsed <- .times$time <= .now()
|
||||
result <- .times[elapsed,]
|
||||
.times <<- .times[!elapsed,]
|
||||
|
||||
# TODO: Examine scheduled column to check if any funny business
|
||||
# has occurred with the system clock (e.g. if scheduled
|
||||
# is later than now())
|
||||
# is later than .now())
|
||||
|
||||
return(result)
|
||||
},
|
||||
@@ -86,6 +87,30 @@ TimerCallbacks <- R6Class(
|
||||
)
|
||||
)
|
||||
|
||||
MockableTimerCallbacks <- R6Class(
|
||||
'MockableTimerCallbacks',
|
||||
inherit = TimerCallbacks,
|
||||
portable = FALSE,
|
||||
class = FALSE,
|
||||
public = list(
|
||||
# Empty constructor defaults to the getNow implementation
|
||||
initialize = function() {
|
||||
super$initialize(self$mockNow)
|
||||
},
|
||||
mockNow = function() {
|
||||
return(private$time)
|
||||
},
|
||||
elapse = function(millis) {
|
||||
private$time <- private$time + millis
|
||||
},
|
||||
getElapsed = function() {
|
||||
private$time
|
||||
}
|
||||
), private = list(
|
||||
time = 0L
|
||||
)
|
||||
)
|
||||
|
||||
timerCallbacks <- TimerCallbacks$new()
|
||||
|
||||
scheduleTask <- function(millis, callback) {
|
||||
@@ -96,3 +121,27 @@ scheduleTask <- function(millis, callback) {
|
||||
invisible(timerCallbacks$unschedule(id))
|
||||
}
|
||||
}
|
||||
|
||||
#' Get a scheduler function for scheduling tasks. Give priority to the
|
||||
#' session scheduler, but if it doesn't exist, use the global one.
|
||||
#' @noRd
|
||||
defineScheduler <- function(session){
|
||||
if (!is.null(session) && !is.null(session$.scheduleTask)){
|
||||
return(session$.scheduleTask)
|
||||
}
|
||||
scheduleTask
|
||||
}
|
||||
|
||||
|
||||
#' Get the current time using the current reactive domain. This will try to use
|
||||
#' the session's .now() method, but if that's not available, it will just return
|
||||
#' the real time (from getTimeMs()). The purpose of this function is to allow
|
||||
#' MockableTimerCallbacks to work.
|
||||
#' @noRd
|
||||
getDomainTimeMs <- function(session){
|
||||
if (!is.null(session) && !is.null(session$.now)){
|
||||
return(session$.now())
|
||||
} else {
|
||||
getTimeMs()
|
||||
}
|
||||
}
|
||||
|
||||
18
R/utils.R
18
R/utils.R
@@ -173,8 +173,8 @@ anyUnnamed <- function(x) {
|
||||
}
|
||||
|
||||
|
||||
# Given a vector/list, returns a named vector (the labels will be blank).
|
||||
asNamedVector <- function(x) {
|
||||
# Given a vector/list, returns a named vector/list (the labels will be blank).
|
||||
asNamed <- function(x) {
|
||||
if (is.null(names(x))) {
|
||||
names(x) <- character(length(x))
|
||||
}
|
||||
@@ -800,7 +800,14 @@ dataTablesJSON <- function(data, req) {
|
||||
|
||||
fdata <- unname(as.matrix(fdata))
|
||||
if (is.character(fdata) && q$escape != 'false') {
|
||||
if (q$escape == 'true') fdata <- htmlEscape(fdata) else {
|
||||
if (q$escape == 'true') {
|
||||
# fdata must be a matrix at this point, and we need to preserve
|
||||
# dimensions. Note that it could be a 1xn matrix.
|
||||
dims <- dim(fdata)
|
||||
fdata <- htmlEscape(fdata)
|
||||
dim(fdata) <- dims
|
||||
|
||||
} else {
|
||||
k <- as.integer(strsplit(q$escape, ',')[[1]])
|
||||
# use seq_len() in case escape = negative indices, e.g. c(-1, -5)
|
||||
for (j in seq_len(ncol(fdata))[k]) fdata[, j] <- htmlEscape(fdata[, j])
|
||||
@@ -1800,3 +1807,8 @@ constantTimeEquals <- function(raw1, raw2) {
|
||||
|
||||
sum(as.integer(xor(raw1, raw2))) == 0
|
||||
}
|
||||
|
||||
cat_line <- function(...) {
|
||||
cat(paste(..., "\n", collapse = ""))
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ The Javascript code in Shiny is minified using tools that run on Node.js. See th
|
||||
|
||||
## Guidelines for contributing
|
||||
|
||||
We welcome contributions to the **shiny** package. Please see our [CONTRIBUTING.md](CONTRIBUTING.md) file for detailed guidelines of how to contribute.
|
||||
We welcome contributions to the **shiny** package. Please see our [CONTRIBUTING.md](https://github.com/rstudio/shiny/blob/master/.github/CONTRIBUTING.md) file for detailed guidelines of how to contribute.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -11,7 +11,12 @@ install:
|
||||
ps: Bootstrap
|
||||
|
||||
cache:
|
||||
- C:\RLibrary
|
||||
# Bust library cache every time the description file changes
|
||||
# as appveyor cache can not be busted manually
|
||||
# This helps get around errors such as "can't update curl because it's already loaded"
|
||||
# when trying to update the existing cache
|
||||
# PR: https://github.com/rstudio/shiny/pull/2722
|
||||
- C:\RLibrary -> DESCRIPTION
|
||||
|
||||
# Adapt as necessary starting from here
|
||||
|
||||
|
||||
221
inst/_pkgdown.yml
Normal file
221
inst/_pkgdown.yml
Normal file
@@ -0,0 +1,221 @@
|
||||
# NOTE: The main Shiny site, https://shiny.rstudio.com/, is not a pkgdown site.
|
||||
# However, as part of the build process for that site
|
||||
# (rstudio/shiny-dev-center), we do use pkgdown to generate the function
|
||||
# reference index pages for each release. This file configures the look of
|
||||
# those pages for releases from 1.4 onward. Prior to 1.4, staticdocs from
|
||||
# https://github.com/r-lib/pkgdown/releases/tag/old was used and
|
||||
# inst/staticdocs/index.r was its configuration.
|
||||
template:
|
||||
# NOTE: These templates live in shiny-dev-center
|
||||
path: _pkgdown_templates
|
||||
reference:
|
||||
- title: UI Layout
|
||||
desc: Functions for laying out the user interface for your application.
|
||||
contents:
|
||||
- absolutePanel
|
||||
- bootstrapPage
|
||||
- column
|
||||
- conditionalPanel
|
||||
- fillPage
|
||||
- fillRow
|
||||
- fixedPage
|
||||
- fluidPage
|
||||
- helpText
|
||||
- icon
|
||||
- navbarPage
|
||||
- navlistPanel
|
||||
- sidebarLayout
|
||||
- tabPanel
|
||||
- tabsetPanel
|
||||
- titlePanel
|
||||
- inputPanel
|
||||
- flowLayout
|
||||
- splitLayout
|
||||
- verticalLayout
|
||||
- wellPanel
|
||||
- withMathJax
|
||||
- title: UI Inputs
|
||||
desc: Functions for creating user interface elements that prompt the user for input values or interaction.
|
||||
contents:
|
||||
- actionButton
|
||||
- checkboxGroupInput
|
||||
- checkboxInput
|
||||
- dateInput
|
||||
- dateRangeInput
|
||||
- fileInput
|
||||
- numericInput
|
||||
- radioButtons
|
||||
- selectInput
|
||||
- varSelectInput
|
||||
- sliderInput
|
||||
- submitButton
|
||||
- textInput
|
||||
- textAreaInput
|
||||
- passwordInput
|
||||
- modalButton
|
||||
- updateActionButton
|
||||
- updateCheckboxGroupInput
|
||||
- updateCheckboxInput
|
||||
- updateDateInput
|
||||
- updateDateRangeInput
|
||||
- updateNumericInput
|
||||
- updateRadioButtons
|
||||
- updateSelectInput
|
||||
- updateSliderInput
|
||||
- updateTabsetPanel
|
||||
- insertTab
|
||||
- showTab
|
||||
- updateTextInput
|
||||
- updateTextAreaInput
|
||||
- updateQueryString
|
||||
- getQueryString
|
||||
- title: UI Outputs
|
||||
desc: Functions for creating user interface elements that, in conjunction with rendering functions, display different kinds of output from your application.
|
||||
contents:
|
||||
- htmlOutput
|
||||
- plotOutput
|
||||
- outputOptions
|
||||
- tableOutput
|
||||
- textOutput
|
||||
- downloadButton
|
||||
- Progress
|
||||
- withProgress
|
||||
- modalDialog
|
||||
- urlModal
|
||||
- showModal
|
||||
- showNotification
|
||||
- title: Interface builder functions
|
||||
desc: A sub-library for writing HTML using R functions. These functions form the foundation on which the higher level user interface functions are built, and can also be used in your Shiny UI to provide custom HTML, CSS, and JavaScript.
|
||||
contents:
|
||||
- builder
|
||||
- HTML
|
||||
- include
|
||||
- singleton
|
||||
- tag
|
||||
- validateCssUnit
|
||||
- withTags
|
||||
- htmlTemplate
|
||||
- bootstrapLib
|
||||
- suppressDependencies
|
||||
- insertUI
|
||||
- title: Rendering functions
|
||||
desc: Functions that you use in your application's server side code, assigning them to outputs that appear in your user interface.
|
||||
contents:
|
||||
- renderPlot
|
||||
- renderCachedPlot
|
||||
- renderText
|
||||
- renderPrint
|
||||
- renderDataTable
|
||||
- renderImage
|
||||
- renderTable
|
||||
- renderUI
|
||||
- downloadHandler
|
||||
- createRenderFunction
|
||||
- title: Reactive programming
|
||||
desc: A sub-library that provides reactive programming facilities for R.
|
||||
contents:
|
||||
- reactive
|
||||
- observe
|
||||
- observeEvent
|
||||
- reactiveVal
|
||||
- reactiveValues
|
||||
- reactiveValuesToList
|
||||
- is.reactivevalues
|
||||
- isolate
|
||||
- invalidateLater
|
||||
- debounce
|
||||
- reactlog
|
||||
- makeReactiveBinding
|
||||
- reactiveFileReader
|
||||
- reactivePoll
|
||||
- reactiveTimer
|
||||
- domains
|
||||
- freezeReactiveValue
|
||||
- title: Boilerplate
|
||||
desc: Functions that are required boilerplate in ui.R and server.R.
|
||||
contents:
|
||||
- shinyUI
|
||||
- shinyServer
|
||||
- title: Running
|
||||
desc: Functions that are used to run or stop Shiny applications.
|
||||
contents:
|
||||
- runApp
|
||||
- runGadget
|
||||
- runExample
|
||||
- runGadget
|
||||
- runUrl
|
||||
- stopApp
|
||||
- viewer
|
||||
- isRunning
|
||||
- loadSupport
|
||||
- title: Bookmarking state
|
||||
desc: Functions that are used for bookmarking and restoring state.
|
||||
contents:
|
||||
- bookmarkButton
|
||||
- enableBookmarking
|
||||
- setBookmarkExclude
|
||||
- showBookmarkUrlModal
|
||||
- onBookmark
|
||||
- title: Extending Shiny
|
||||
desc: Functions that are intended to be called by third-party packages that extend Shiny.
|
||||
contents:
|
||||
- createWebDependency
|
||||
- resourcePaths
|
||||
- registerInputHandler
|
||||
- removeInputHandler
|
||||
- markRenderFunction
|
||||
- title: Utility functions
|
||||
desc: Miscellaneous utilities that may be useful to advanced users or when extending Shiny.
|
||||
contents:
|
||||
- req
|
||||
- validate
|
||||
- session
|
||||
- shinyOptions
|
||||
- safeError
|
||||
- onFlush
|
||||
- restoreInput
|
||||
- applyInputHandlers
|
||||
- exprToFunction
|
||||
- installExprFunction
|
||||
- parseQueryString
|
||||
- getCurrentOutputInfo
|
||||
- plotPNG
|
||||
- sizeGrowthRatio
|
||||
- exportTestValues
|
||||
- setSerializer
|
||||
- snapshotExclude
|
||||
- snapshotPreprocessInput
|
||||
- snapshotPreprocessOutput
|
||||
- markOutputAttrs
|
||||
- repeatable
|
||||
- shinyDeprecated
|
||||
- serverInfo
|
||||
- onStop
|
||||
- diskCache
|
||||
- memoryCache
|
||||
- reexports
|
||||
- title: Plot interaction
|
||||
desc: Functions related to interactive plots
|
||||
contents:
|
||||
- brushedPoints
|
||||
- brushOpts
|
||||
- clickOpts
|
||||
- dblclickOpts
|
||||
- hoverOpts
|
||||
- nearPoints
|
||||
- title: Modules
|
||||
desc: Functions for modularizing Shiny apps
|
||||
contents:
|
||||
- NS
|
||||
- moduleServer
|
||||
- title: Embedding
|
||||
desc: Functions that are intended for third-party packages that embed Shiny applications.
|
||||
contents:
|
||||
- shinyApp
|
||||
- maskReactiveContext
|
||||
- title: Testing
|
||||
desc: Functions intended for testing of Shiny components
|
||||
contents:
|
||||
- runTests
|
||||
- testModule
|
||||
- MockShinySession
|
||||
@@ -1,238 +0,0 @@
|
||||
sd_section("UI Layout",
|
||||
"Functions for laying out the user interface for your application.",
|
||||
c(
|
||||
"absolutePanel",
|
||||
"bootstrapPage",
|
||||
"column",
|
||||
"conditionalPanel",
|
||||
"fillPage",
|
||||
"fillRow",
|
||||
"fixedPage",
|
||||
"fluidPage",
|
||||
"headerPanel",
|
||||
"helpText",
|
||||
"icon",
|
||||
"mainPanel",
|
||||
"navbarPage",
|
||||
"navlistPanel",
|
||||
"pageWithSidebar",
|
||||
"sidebarLayout",
|
||||
"sidebarPanel",
|
||||
"tabPanel",
|
||||
"tabsetPanel",
|
||||
"titlePanel",
|
||||
"inputPanel",
|
||||
"flowLayout",
|
||||
"splitLayout",
|
||||
"verticalLayout",
|
||||
"wellPanel",
|
||||
"withMathJax"
|
||||
)
|
||||
)
|
||||
sd_section("UI Inputs",
|
||||
"Functions for creating user interface elements that prompt the user for input values or interaction.",
|
||||
c(
|
||||
"actionButton",
|
||||
"checkboxGroupInput",
|
||||
"checkboxInput",
|
||||
"dateInput",
|
||||
"dateRangeInput",
|
||||
"fileInput",
|
||||
"numericInput",
|
||||
"radioButtons",
|
||||
"selectInput",
|
||||
"varSelectInput",
|
||||
"sliderInput",
|
||||
"submitButton",
|
||||
"textInput",
|
||||
"textAreaInput",
|
||||
"passwordInput",
|
||||
"modalButton",
|
||||
"updateActionButton",
|
||||
"updateCheckboxGroupInput",
|
||||
"updateCheckboxInput",
|
||||
"updateDateInput",
|
||||
"updateDateRangeInput",
|
||||
"updateNumericInput",
|
||||
"updateRadioButtons",
|
||||
"updateSelectInput",
|
||||
"updateSliderInput",
|
||||
"updateTabsetPanel",
|
||||
"insertTab",
|
||||
"showTab",
|
||||
"updateTextInput",
|
||||
"updateTextAreaInput",
|
||||
"updateQueryString",
|
||||
"getQueryString"
|
||||
)
|
||||
)
|
||||
sd_section("UI Outputs",
|
||||
"Functions for creating user interface elements that, in conjunction with rendering functions, display different kinds of output from your application.",
|
||||
c(
|
||||
"htmlOutput",
|
||||
"plotOutput",
|
||||
"outputOptions",
|
||||
"tableOutput",
|
||||
"textOutput",
|
||||
"verbatimTextOutput",
|
||||
"downloadButton",
|
||||
"Progress",
|
||||
"withProgress",
|
||||
"modalDialog",
|
||||
"urlModal",
|
||||
"showModal",
|
||||
"showNotification"
|
||||
)
|
||||
)
|
||||
sd_section("Interface builder functions",
|
||||
"A sub-library for writing HTML using R functions. These functions form the foundation on which the higher level user interface functions are built, and can also be used in your Shiny UI to provide custom HTML, CSS, and JavaScript.",
|
||||
c(
|
||||
"builder",
|
||||
"HTML",
|
||||
"include",
|
||||
"singleton",
|
||||
"tag",
|
||||
"validateCssUnit",
|
||||
"withTags",
|
||||
"htmlTemplate",
|
||||
"bootstrapLib",
|
||||
"suppressDependencies",
|
||||
"insertUI",
|
||||
"removeUI"
|
||||
)
|
||||
)
|
||||
sd_section("Rendering functions",
|
||||
"Functions that you use in your application's server side code, assigning them to outputs that appear in your user interface.",
|
||||
c(
|
||||
"renderPlot",
|
||||
"renderCachedPlot",
|
||||
"renderText",
|
||||
"renderPrint",
|
||||
"renderDataTable",
|
||||
"renderImage",
|
||||
"renderTable",
|
||||
"renderUI",
|
||||
"downloadHandler",
|
||||
"createRenderFunction"
|
||||
)
|
||||
)
|
||||
sd_section("Reactive programming",
|
||||
"A sub-library that provides reactive programming facilities for R.",
|
||||
c(
|
||||
"reactive",
|
||||
"observe",
|
||||
"observeEvent",
|
||||
"reactiveVal",
|
||||
"reactiveValues",
|
||||
"reactiveValuesToList",
|
||||
"is.reactivevalues",
|
||||
"isolate",
|
||||
"invalidateLater",
|
||||
"debounce",
|
||||
"reactlog",
|
||||
"makeReactiveBinding",
|
||||
"reactiveFileReader",
|
||||
"reactivePoll",
|
||||
"reactiveTimer",
|
||||
"domains",
|
||||
"freezeReactiveValue"
|
||||
)
|
||||
)
|
||||
sd_section("Boilerplate",
|
||||
"Functions that are required boilerplate in ui.R and server.R.",
|
||||
c(
|
||||
"shinyUI",
|
||||
"shinyServer"
|
||||
)
|
||||
)
|
||||
sd_section("Running",
|
||||
"Functions that are used to run or stop Shiny applications.",
|
||||
c(
|
||||
"runApp",
|
||||
"runGadget",
|
||||
"runExample",
|
||||
"runGadget",
|
||||
"runUrl",
|
||||
"stopApp",
|
||||
"viewer",
|
||||
"isRunning"
|
||||
)
|
||||
)
|
||||
sd_section("Bookmarking state",
|
||||
"Functions that are used for bookmarking and restoring state.",
|
||||
c(
|
||||
"bookmarkButton",
|
||||
"enableBookmarking",
|
||||
"setBookmarkExclude",
|
||||
"showBookmarkUrlModal",
|
||||
"onBookmark"
|
||||
)
|
||||
)
|
||||
sd_section("Extending Shiny",
|
||||
"Functions that are intended to be called by third-party packages that extend Shiny.",
|
||||
c(
|
||||
"createWebDependency",
|
||||
"addResourcePath",
|
||||
"registerInputHandler",
|
||||
"removeInputHandler",
|
||||
"markRenderFunction"
|
||||
)
|
||||
)
|
||||
sd_section("Utility functions",
|
||||
"Miscellaneous utilities that may be useful to advanced users or when extending Shiny.",
|
||||
c(
|
||||
"req",
|
||||
"validate",
|
||||
"session",
|
||||
"shinyOptions",
|
||||
"safeError",
|
||||
"onFlush",
|
||||
"restoreInput",
|
||||
"applyInputHandlers",
|
||||
"exprToFunction",
|
||||
"installExprFunction",
|
||||
"parseQueryString",
|
||||
"getCurrentOutputInfo",
|
||||
"plotPNG",
|
||||
"sizeGrowthRatio",
|
||||
"exportTestValues",
|
||||
"setSerializer",
|
||||
"snapshotExclude",
|
||||
"snapshotPreprocessInput",
|
||||
"snapshotPreprocessOutput",
|
||||
"markOutputAttrs",
|
||||
"repeatable",
|
||||
"shinyDeprecated",
|
||||
"serverInfo",
|
||||
"shiny-options",
|
||||
"onStop",
|
||||
"diskCache",
|
||||
"memoryCache",
|
||||
"reexports"
|
||||
)
|
||||
)
|
||||
sd_section("Plot interaction",
|
||||
"Functions related to interactive plots",
|
||||
c(
|
||||
"brushedPoints",
|
||||
"brushOpts",
|
||||
"clickOpts",
|
||||
"dblclickOpts",
|
||||
"hoverOpts",
|
||||
"nearPoints"
|
||||
)
|
||||
)
|
||||
sd_section("Modules",
|
||||
"Functions for modularizing Shiny apps",
|
||||
c(
|
||||
"NS",
|
||||
"callModule"
|
||||
)
|
||||
)
|
||||
sd_section("Embedding",
|
||||
"Functions that are intended for third-party packages that embed Shiny applications.",
|
||||
c(
|
||||
"shinyApp",
|
||||
"maskReactiveContext"
|
||||
)
|
||||
)
|
||||
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
@@ -29,8 +29,8 @@ $.extend( true, DataTable.defaults, {
|
||||
/* Default class modification */
|
||||
$.extend( DataTable.ext.classes, {
|
||||
sWrapper: "dataTables_wrapper form-inline dt-bootstrap",
|
||||
sFilterInput: "form-control input-sm",
|
||||
sLengthSelect: "form-control input-sm"
|
||||
sFilterInput: "form-control form-control-sm input-sm",
|
||||
sLengthSelect: "form-control form-control-sm input-sm"
|
||||
} );
|
||||
|
||||
|
||||
|
||||
@@ -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
266
inst/www/shared/legacy/jquery-AUTHORS.txt
Normal file
266
inst/www/shared/legacy/jquery-AUTHORS.txt
Normal file
@@ -0,0 +1,266 @@
|
||||
Authors ordered by first contribution.
|
||||
|
||||
John Resig <jeresig@gmail.com>
|
||||
Gilles van den Hoven <gilles0181@gmail.com>
|
||||
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>
|
||||
Franck Marcia <franck.marcia@gmail.com>
|
||||
Jörn Zaefferer <joern.zaefferer@gmail.com>
|
||||
Paul Bakaus <paul.bakaus@googlemail.com>
|
||||
Brandon Aaron <brandon.aaron@gmail.com>
|
||||
Mike Alsup <malsup@gmail.com>
|
||||
Dave Methvin <dave.methvin@gmail.com>
|
||||
Ed Engelhardt <edengelhardt@gmail.com>
|
||||
Sean Catchpole <littlecooldude@gmail.com>
|
||||
Paul Mclanahan <pmclanahan@gmail.com>
|
||||
David Serduke <davidserduke@gmail.com>
|
||||
Richard D. Worth <rdworth@gmail.com>
|
||||
Scott González <scott.gonzalez@gmail.com>
|
||||
Ariel Flesler <aflesler@gmail.com>
|
||||
Jon Evans <jon@springyweb.com>
|
||||
TJ Holowaychuk <tj@vision-media.ca>
|
||||
Michael Bensoussan <mickey@seesmic.com>
|
||||
Robert Katić <robert.katic@gmail.com>
|
||||
Louis-Rémi Babé <lrbabe@gmail.com>
|
||||
Earle Castledine <mrspeaker@gmail.com>
|
||||
Damian Janowski <damian.janowski@gmail.com>
|
||||
Rich Dougherty <rich@rd.gen.nz>
|
||||
Kim Dalsgaard <kim@kimdalsgaard.com>
|
||||
Andrea Giammarchi <andrea.giammarchi@gmail.com>
|
||||
Mark Gibson <jollytoad@gmail.com>
|
||||
Karl Swedberg <kswedberg@gmail.com>
|
||||
Justin Meyer <justinbmeyer@gmail.com>
|
||||
Ben Alman <cowboy@rj3.net>
|
||||
James Padolsey <cla@padolsey.net>
|
||||
David Petersen <public@petersendidit.com>
|
||||
Batiste Bieler <batiste.bieler@gmail.com>
|
||||
Alexander Farkas <info@corrupt-system.de>
|
||||
Rick Waldron <waldron.rick@gmail.com>
|
||||
Filipe Fortes <filipe@fortes.com>
|
||||
Neeraj Singh <neerajdotname@gmail.com>
|
||||
Paul Irish <paul.irish@gmail.com>
|
||||
Iraê Carvalho <irae@irae.pro.br>
|
||||
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>
|
||||
Adam J. Sontag <ajpiano@ajpiano.com>
|
||||
Dave Reed <dareed@microsoft.com>
|
||||
Ralph Whitbeck <ralph.whitbeck@gmail.com>
|
||||
Carl Fürstenberg <azatoth@gmail.com>
|
||||
Jacob Wright <jacwright@gmail.com>
|
||||
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>
|
||||
Ryan W Tenney <ryan@10e.us>
|
||||
Pinhook <contact@pinhooklabs.com>
|
||||
Ron Otten <r.j.g.otten@gmail.com>
|
||||
Jephte Clain <Jephte.Clain@univ-reunion.fr>
|
||||
Anton Matzneller <obhvsbypqghgc@gmail.com>
|
||||
Alex Sexton <AlexSexton@gmail.com>
|
||||
Dan Heberden <danheberden@gmail.com>
|
||||
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>
|
||||
James Burke <jrburke@gmail.com>
|
||||
Jonas Pfenniger <jonas@pfenniger.name>
|
||||
Xavi Ramirez <xavi.rmz@gmail.com>
|
||||
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>
|
||||
Digitalxero <digitalxero>
|
||||
Anton Kovalyov <anton@kovalyov.net>
|
||||
David Murdoch <musicisair@yahoo.com>
|
||||
Josh Varner <josh.varner@gmail.com>
|
||||
Charles McNulty <cmcnulty@kznf.com>
|
||||
Jordan Boesch <jboesch26@gmail.com>
|
||||
Jess Thrysoee <jess@thrysoee.dk>
|
||||
Michael Murray <m@murz.net>
|
||||
Lee Carpenter <elcarpie@gmail.com>
|
||||
Alexis Abril <me@alexisabril.com>
|
||||
Rob Morgan <robbym@gmail.com>
|
||||
John Firebaugh <john_firebaugh@bigfix.com>
|
||||
Sam Bisbee <sam@sbisbee.com>
|
||||
Gilmore Davidson <gilmoreorless@gmail.com>
|
||||
Brian Brennan <me@brianlovesthings.com>
|
||||
Xavier Montillet <xavierm02.net@gmail.com>
|
||||
Daniel Pihlstrom <sciolist.se@gmail.com>
|
||||
Sahab Yazdani <sahab.yazdani+github@gmail.com>
|
||||
avaly <github-com@agachi.name>
|
||||
Scott Hughes <hi@scott-hughes.me>
|
||||
Mike Sherov <mike.sherov@gmail.com>
|
||||
Greg Hazel <ghazel@gmail.com>
|
||||
Schalk Neethling <schalk@ossreleasefeed.com>
|
||||
Denis Knauf <Denis.Knauf@gmail.com>
|
||||
Timo Tijhof <krinklemail@gmail.com>
|
||||
Steen Nielsen <swinedk@gmail.com>
|
||||
Anton Ryzhov <anton@ryzhov.me>
|
||||
Shi Chuan <shichuanr@gmail.com>
|
||||
Berker Peksag <berker.peksag@gmail.com>
|
||||
Toby Brain <tobyb@freshview.com>
|
||||
Matt Mueller <mattmuelle@gmail.com>
|
||||
Justin <drakefjustin@gmail.com>
|
||||
Daniel Herman <daniel.c.herman@gmail.com>
|
||||
Oleg Gaidarenko <markelog@gmail.com>
|
||||
Richard Gibson <richard.gibson@gmail.com>
|
||||
Rafaël Blais Masson <rafbmasson@gmail.com>
|
||||
cmc3cn <59194618@qq.com>
|
||||
Joe Presbrey <presbrey@gmail.com>
|
||||
Sindre Sorhus <sindresorhus@gmail.com>
|
||||
Arne de Bree <arne@bukkie.nl>
|
||||
Vladislav Zarakovsky <vlad.zar@gmail.com>
|
||||
Andrew E Monat <amonat@gmail.com>
|
||||
Oskari <admin@o-programs.com>
|
||||
Joao Henrique de Andrade Bruni <joaohbruni@yahoo.com.br>
|
||||
tsinha <tsinha@Anthonys-MacBook-Pro.local>
|
||||
Matt Farmer <matt@frmr.me>
|
||||
Trey Hunner <treyhunner@gmail.com>
|
||||
Jason Moon <jmoon@socialcast.com>
|
||||
Jeffery To <jeffery.to@gmail.com>
|
||||
Kris Borchers <kris.borchers@gmail.com>
|
||||
Vladimir Zhuravlev <private.face@gmail.com>
|
||||
Jacob Thornton <jacobthornton@gmail.com>
|
||||
Chad Killingsworth <chadkillingsworth@missouristate.edu>
|
||||
Nowres Rafid <nowres.rafed@gmail.com>
|
||||
David Benjamin <davidben@mit.edu>
|
||||
Uri Gilad <antishok@gmail.com>
|
||||
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>
|
||||
Mike Pennisi <mike@mikepennisi.com>
|
||||
Markus Staab <markus.staab@redaxo.de>
|
||||
Dave Riddle <david@joyvuu.com>
|
||||
Callum Macrae <callum@lynxphp.com>
|
||||
Benjamin Truyman <bentruyman@gmail.com>
|
||||
James Huston <james@jameshuston.net>
|
||||
Erick Ruiz de Chávez <erickrdch@gmail.com>
|
||||
David Bonner <dbonner@cogolabs.com>
|
||||
Akintayo Akinwunmi <aakinwunmi@judge.com>
|
||||
MORGAN <morgan@morgangraphics.com>
|
||||
Ismail Khair <ismail.khair@gmail.com>
|
||||
Carl Danley <carldanley@gmail.com>
|
||||
Mike Petrovich <michael.c.petrovich@gmail.com>
|
||||
Greg Lavallee <greglavallee@wapolabs.com>
|
||||
Daniel Gálvez <dgalvez@editablething.com>
|
||||
Sai Lung Wong <sai.wong@huffingtonpost.com>
|
||||
Tom H Fuertes <TomFuertes@gmail.com>
|
||||
Roland Eckl <eckl.roland@googlemail.com>
|
||||
Jay Merrifield <fracmak@gmail.com>
|
||||
Allen J Schmidt Jr <cobrasoft@gmail.com>
|
||||
Jonathan Sampson <jjdsampson@gmail.com>
|
||||
Marcel Greter <marcel.greter@ocbnet.ch>
|
||||
Matthias Jäggli <matthias.jaeggli@gmail.com>
|
||||
David Fox <dfoxinator@gmail.com>
|
||||
Yiming He <yiminghe@gmail.com>
|
||||
Devin Cooper <cooper.semantics@gmail.com>
|
||||
Paul Ramos <paul.b.ramos@gmail.com>
|
||||
Rod Vagg <rod@vagg.org>
|
||||
Bennett Sorbo <bsorbo@gmail.com>
|
||||
Sebastian Burkhard <sebi.burkhard@gmail.com>
|
||||
nanto <nanto@moon.email.ne.jp>
|
||||
Danil Somsikov <danilasomsikov@gmail.com>
|
||||
Ryunosuke SATO <tricknotes.rs@gmail.com>
|
||||
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>
|
||||
Nguyen Phuc Lam <ruado1987@gmail.com>
|
||||
Tom H Fuertes <tomfuertes@gmail.com>
|
||||
Brandon Johnson <bjohn465+github@gmail.com>
|
||||
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>
|
||||
Amey Sakhadeo <me@ameyms.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>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
George Mauer <gmauer@gmail.com>
|
||||
Leonardo Braga <leonardo.braga@gmail.com>
|
||||
Stephen Edgar <stephen@netweb.com.au>
|
||||
Thomas Tortorini <thomastortorini@gmail.com>
|
||||
Winston Howes <winstonhowes@gmail.com>
|
||||
Jon Hester <jon.d.hester@gmail.com>
|
||||
Alexander O'Mara <me@alexomara.com>
|
||||
Bastian Buchholz <buchholz.bastian@googlemail.com>
|
||||
Arthur Stolyar <nekr.fabula@gmail.com>
|
||||
Calvin Metcalf <calvin.metcalf@gmail.com>
|
||||
Mu Haibao <mhbseal@163.com>
|
||||
Richard McDaniel <rm0026@uah.edu>
|
||||
Chris Rebert <github@rebertia.com>
|
||||
Gilad Peleg <giladp007@gmail.com>
|
||||
Martin Naumann <martin@geekonaut.de>
|
||||
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>
|
||||
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>
|
||||
Jun Sun <klsforever@gmail.com>
|
||||
Devin Wilson <dwilson6.github@gmail.com>
|
||||
Todor Prikumov <tono_pr@abv.bg>
|
||||
Zack Hall <zackhall@outlook.com>
|
||||
11008
inst/www/shared/legacy/jquery.js
vendored
Normal file
11008
inst/www/shared/legacy/jquery.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5
inst/www/shared/legacy/jquery.min.js
vendored
Normal file
5
inst/www/shared/legacy/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
inst/www/shared/legacy/jquery.min.map
Normal file
1
inst/www/shared/legacy/jquery.min.map
Normal file
File diff suppressed because one or more lines are too long
@@ -83,6 +83,8 @@
|
||||
el.id = "srcref_" + srcref;
|
||||
var ref = srcref;
|
||||
var code = document.getElementById(srcfile.replace(/\./g, "_") + "_code");
|
||||
// if there is no code file (might be a shiny file), quit early
|
||||
if (!code) return;
|
||||
var start = findTextPoint(code, ref[0], ref[4]);
|
||||
var end = findTextPoint(code, ref[2], ref[5]);
|
||||
|
||||
@@ -117,7 +119,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);
|
||||
}
|
||||
@@ -148,6 +150,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
// hide the new element before doing anything to it
|
||||
$(newHostElement).hide();
|
||||
$(currentHostElement).fadeOut(animateCodeMs, function() {
|
||||
var tabs = document.getElementById("showcase-code-tabs");
|
||||
currentHostElement.removeChild(tabs);
|
||||
@@ -160,7 +164,7 @@
|
||||
document.getElementById("showcase-code-content").removeAttribute("style");
|
||||
}
|
||||
|
||||
$(newHostElement).fadeIn();
|
||||
$(newHostElement).fadeIn(animateCodeMs);
|
||||
if (!above) {
|
||||
// remove the applied width and zoom on the app container, and
|
||||
// scroll smoothly down to the code's new home
|
||||
@@ -189,7 +193,6 @@
|
||||
if (above) {
|
||||
$(document.body).animate({ scrollTop: 0 }, animateCodeMs);
|
||||
}
|
||||
$(newHostElement).hide();
|
||||
isCodeAbove = above;
|
||||
setAppCodeSxsWidths(above && animate);
|
||||
$(window).trigger("resize");
|
||||
@@ -267,4 +270,3 @@
|
||||
if (window.hljs)
|
||||
hljs.initHighlightingOnLoad();
|
||||
})();
|
||||
|
||||
|
||||
@@ -401,6 +401,9 @@ pre.shiny-text-output {
|
||||
/* Overrides bootstrap-datepicker3.css styling for invalid date ranges.
|
||||
See https://github.com/rstudio/shiny/issues/2042 for details. */
|
||||
.datepicker table tbody tr td.disabled,
|
||||
.datepicker table tbody tr td.disabled:hover {
|
||||
.datepicker table tbody tr td.disabled:hover,
|
||||
.datepicker table tbody tr td span.disabled,
|
||||
.datepicker table tbody tr td span.disabled:hover {
|
||||
color: #aaa;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
||||
|
||||
var exports = window.Shiny = window.Shiny || {};
|
||||
|
||||
exports.version = "1.3.2.9001"; // Version number inserted by Grunt
|
||||
exports.version = "1.4.0.9002"; // Version number inserted by Grunt
|
||||
|
||||
var origPushState = window.history.pushState;
|
||||
window.history.pushState = function () {
|
||||
@@ -611,7 +611,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
||||
return;
|
||||
}
|
||||
this.lastSentValues[inputName] = { jsonValue: jsonValue, inputType: inputType };
|
||||
this.target.setInput(name, value, opts);
|
||||
this.target.setInput(nameType, value, opts);
|
||||
};
|
||||
this.reset = function () {
|
||||
var values = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
||||
@@ -626,10 +626,10 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
||||
for (var inputName in values) {
|
||||
if (values.hasOwnProperty(inputName)) {
|
||||
var _splitInputNameType2 = splitInputNameType(inputName),
|
||||
_name = _splitInputNameType2.name,
|
||||
name = _splitInputNameType2.name,
|
||||
inputType = _splitInputNameType2.inputType;
|
||||
|
||||
cacheValues[_name] = {
|
||||
cacheValues[name] = {
|
||||
jsonValue: JSON.stringify(values[inputName]),
|
||||
inputType: inputType
|
||||
};
|
||||
@@ -658,7 +658,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
||||
$(opts.el).trigger(evt);
|
||||
|
||||
if (!evt.isDefaultPrevented()) {
|
||||
name = evt.name;
|
||||
var name = evt.name;
|
||||
if (evt.inputType !== '') name += ':' + evt.inputType;
|
||||
|
||||
// Most opts aren't passed along to lower levels in the input decorator
|
||||
@@ -713,13 +713,16 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
||||
};
|
||||
(function () {
|
||||
this.setInput = function (nameType, value, opts) {
|
||||
if (/^\./.test(nameType)) this.target.setInput(nameType, value, opts);else this.pendingInput[name] = { value: value, opts: opts };
|
||||
if (/^\./.test(nameType)) this.target.setInput(nameType, value, opts);else this.pendingInput[nameType] = { value: value, opts: opts };
|
||||
};
|
||||
this.submit = function () {
|
||||
for (var name in this.pendingInput) {
|
||||
if (this.pendingInput.hasOwnProperty(name)) {
|
||||
var input = this.pendingInput[name];
|
||||
this.target.setInput(name, input.value, input.opts);
|
||||
for (var nameType in this.pendingInput) {
|
||||
if (this.pendingInput.hasOwnProperty(nameType)) {
|
||||
var _pendingInput$nameTyp = this.pendingInput[nameType],
|
||||
value = _pendingInput$nameTyp.value,
|
||||
opts = _pendingInput$nameTyp.opts;
|
||||
|
||||
this.target.setInput(nameType, value, opts);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1600,13 +1603,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));
|
||||
}
|
||||
});
|
||||
@@ -1788,7 +1793,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
||||
// Progress bar starts hidden; will be made visible if a value is provided
|
||||
// during updates.
|
||||
exports.notifications.show({
|
||||
html: "<div id=\"shiny-progress-" + message.id + "\" class=\"shiny-progress-notification\">" + '<div class="progress progress-striped active" style="display: none;"><div class="progress-bar"></div></div>' + '<div class="progress-text">' + '<span class="progress-message">message</span> ' + '<span class="progress-detail"></span>' + '</div>' + '</div>',
|
||||
html: "<div id=\"shiny-progress-" + message.id + "\" class=\"shiny-progress-notification\">" + '<div class="progress active" style="display: none;"><div class="progress-bar"></div></div>' + '<div class="progress-text">' + '<span class="progress-message">message</span> ' + '<span class="progress-detail"></span>' + '</div>' + '</div>',
|
||||
id: message.id,
|
||||
duration: null
|
||||
});
|
||||
@@ -1805,7 +1810,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
||||
// Add div for just this progress ID
|
||||
var depth = $('.shiny-progress.open').length;
|
||||
// The 'bar' class is needed for backward compatibility with Bootstrap 2.
|
||||
var $progress = $('<div class="shiny-progress open">' + '<div class="progress progress-striped active"><div class="progress-bar bar"></div></div>' + '<div class="progress-text">' + '<span class="progress-message">message</span>' + '<span class="progress-detail"></span>' + '</div>' + '</div>');
|
||||
var $progress = $('<div class="shiny-progress open">' + '<div class="progress active"><div class="progress-bar bar"></div></div>' + '<div class="progress-text">' + '<span class="progress-message">message</span>' + '<span class="progress-detail"></span>' + '</div>' + '</div>');
|
||||
|
||||
$progress.attr('id', message.id);
|
||||
$container.append($progress);
|
||||
@@ -2997,9 +3002,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
||||
var e2 = $.Event(newEventType, {
|
||||
which: e.which,
|
||||
pageX: e.pageX,
|
||||
pageY: e.pageY,
|
||||
offsetX: e.offsetX,
|
||||
offsetY: e.offsetY
|
||||
pageY: e.pageY
|
||||
});
|
||||
|
||||
$el.trigger(e2);
|
||||
@@ -3046,7 +3049,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
||||
// If second click is too far away, it doesn't count as a double
|
||||
// click. Instead, immediately trigger a mousedown2 for the previous
|
||||
// click, and set this click as a new first click.
|
||||
if (pending_e && Math.abs(pending_e.offsetX - e.offsetX) > 2 || Math.abs(pending_e.offsetY - e.offsetY) > 2) {
|
||||
if (pending_e && Math.abs(pending_e.pageX - e.pageX) > 2 || Math.abs(pending_e.pageY - e.pageY) > 2) {
|
||||
|
||||
triggerPendingMousedown2();
|
||||
scheduleMousedown2(e);
|
||||
@@ -4918,18 +4921,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 +4956,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
|
||||
@@ -6563,7 +6594,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
||||
initialValues['.clientdata_url_hash'] = window.location.hash;
|
||||
|
||||
$(window).on('hashchange', function (e) {
|
||||
inputs.setInput('.clientdata_url_hash', location.hash);
|
||||
inputs.setInput('.clientdata_url_hash', window.location.hash);
|
||||
});
|
||||
|
||||
// The server needs to know what singletons were rendered as part of
|
||||
@@ -6629,7 +6660,16 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
||||
});
|
||||
|
||||
$(document).on('keydown', function (e) {
|
||||
if (e.which !== 115 || !e.ctrlKey && !e.metaKey || e.shiftKey || e.altKey) return;
|
||||
if (
|
||||
// if not one of the key combos below
|
||||
!(
|
||||
// cmd/ctrl + fn + f4
|
||||
e.which === 115 && (e.ctrlKey || e.metaKey) && !e.shiftKey && !e.altKey ||
|
||||
// cmd/ctrl + shift + fn + f3
|
||||
e.which === 114 && (e.ctrlKey || e.metaKey) && e.shiftKey && !e.altKey)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var url = 'reactlog/mark?w=' + window.escape(exports.shinyapp.config.workerId) + "&s=" + window.escape(exports.shinyapp.config.sessionId);
|
||||
|
||||
// send notification
|
||||
@@ -6642,6 +6682,9 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
||||
html: html,
|
||||
closeButton: true
|
||||
});
|
||||
}).fail(function () {
|
||||
// found returned error while marking, should open webpage
|
||||
window.open(url);
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
File diff suppressed because one or more lines are too long
8
inst/www/shared/shiny.min.js
vendored
8
inst/www/shared/shiny.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -2,13 +2,18 @@
|
||||
\alias{HTML}
|
||||
\title{Mark Characters as HTML}
|
||||
\usage{
|
||||
HTML(text, ...)
|
||||
HTML(text, ..., .noWS = NULL)
|
||||
}
|
||||
\arguments{
|
||||
\item{text}{The text value to mark with HTML}
|
||||
|
||||
\item{...}{Any additional values to be converted to character and
|
||||
concatenated together}
|
||||
|
||||
\item{.noWS}{Character vector used to omit some of the whitespace that would
|
||||
normally be written around this HTML. Valid options include \code{before},
|
||||
\code{after}, and \code{outside} (equivalent to \code{before} and
|
||||
\code{end}).}
|
||||
}
|
||||
\value{
|
||||
The same value, but marked as HTML.
|
||||
@@ -20,5 +25,5 @@ not to perform HTML escaping on it.
|
||||
\examples{
|
||||
el <- div(HTML("I like <u>turtles</u>"))
|
||||
cat(as.character(el))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
687
man/MockShinySession.Rd
Normal file
687
man/MockShinySession.Rd
Normal file
@@ -0,0 +1,687 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/mock-session.R
|
||||
\name{MockShinySession}
|
||||
\alias{MockShinySession}
|
||||
\title{Mock Shiny Session}
|
||||
\description{
|
||||
An R6 class suitable for testing that simulates the \code{session} parameter
|
||||
provided to Shiny server functions or modules.
|
||||
}
|
||||
\examples{
|
||||
|
||||
## ------------------------------------------------
|
||||
## Method `MockShinySession$setInputs`
|
||||
## ------------------------------------------------
|
||||
|
||||
s <- MockShinySession$new()
|
||||
s$setInputs(x=1, y=2)
|
||||
}
|
||||
\section{Public fields}{
|
||||
\if{html}{\out{<div class="r6-fields">}}
|
||||
\describe{
|
||||
\item{\code{env}}{The environment associated with the session.}
|
||||
|
||||
\item{\code{singletons}}{Hardcoded as empty. Needed for rendering HTML (i.e. renderUI)}
|
||||
|
||||
\item{\code{clientData}}{Mock client data that always returns a size for plots}
|
||||
|
||||
\item{\code{output}}{The shinyoutputs associated with the session}
|
||||
|
||||
\item{\code{input}}{The reactive inputs associated with the session}
|
||||
|
||||
\item{\code{userData}}{An environment initialized as empty.}
|
||||
|
||||
\item{\code{progressStack}}{A stack of progress objects}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
\section{Active bindings}{
|
||||
\if{html}{\out{<div class="r6-active-bindings">}}
|
||||
\describe{
|
||||
\item{\code{returned}}{The value returned from the module}
|
||||
|
||||
\item{\code{request}}{An empty environment where the request should be. The request isn't meaningfully mocked currently.}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
\section{Methods}{
|
||||
\subsection{Public methods}{
|
||||
\itemize{
|
||||
\item \href{#method-reactlog}{\code{MockShinySession$reactlog()}}
|
||||
\item \href{#method-incrementBusyCount}{\code{MockShinySession$incrementBusyCount()}}
|
||||
\item \href{#method-new}{\code{MockShinySession$new()}}
|
||||
\item \href{#method-onFlush}{\code{MockShinySession$onFlush()}}
|
||||
\item \href{#method-onFlushed}{\code{MockShinySession$onFlushed()}}
|
||||
\item \href{#method-onEnded}{\code{MockShinySession$onEnded()}}
|
||||
\item \href{#method-isEnded}{\code{MockShinySession$isEnded()}}
|
||||
\item \href{#method-isClosed}{\code{MockShinySession$isClosed()}}
|
||||
\item \href{#method-close}{\code{MockShinySession$close()}}
|
||||
\item \href{#method-cycleStartAction}{\code{MockShinySession$cycleStartAction()}}
|
||||
\item \href{#method-fileUrl}{\code{MockShinySession$fileUrl()}}
|
||||
\item \href{#method-setInputs}{\code{MockShinySession$setInputs()}}
|
||||
\item \href{#method-.scheduleTask}{\code{MockShinySession$.scheduleTask()}}
|
||||
\item \href{#method-elapse}{\code{MockShinySession$elapse()}}
|
||||
\item \href{#method-.now}{\code{MockShinySession$.now()}}
|
||||
\item \href{#method-defineOutput}{\code{MockShinySession$defineOutput()}}
|
||||
\item \href{#method-getOutput}{\code{MockShinySession$getOutput()}}
|
||||
\item \href{#method-registerDataObj}{\code{MockShinySession$registerDataObj()}}
|
||||
\item \href{#method-allowReconnect}{\code{MockShinySession$allowReconnect()}}
|
||||
\item \href{#method-reload}{\code{MockShinySession$reload()}}
|
||||
\item \href{#method-resetBrush}{\code{MockShinySession$resetBrush()}}
|
||||
\item \href{#method-sendCustomMessage}{\code{MockShinySession$sendCustomMessage()}}
|
||||
\item \href{#method-sendBinaryMessage}{\code{MockShinySession$sendBinaryMessage()}}
|
||||
\item \href{#method-sendInputMessage}{\code{MockShinySession$sendInputMessage()}}
|
||||
\item \href{#method-setBookmarkExclude}{\code{MockShinySession$setBookmarkExclude()}}
|
||||
\item \href{#method-getBookmarkExclude}{\code{MockShinySession$getBookmarkExclude()}}
|
||||
\item \href{#method-onBookmark}{\code{MockShinySession$onBookmark()}}
|
||||
\item \href{#method-onBookmarked}{\code{MockShinySession$onBookmarked()}}
|
||||
\item \href{#method-doBookmark}{\code{MockShinySession$doBookmark()}}
|
||||
\item \href{#method-onRestore}{\code{MockShinySession$onRestore()}}
|
||||
\item \href{#method-onRestored}{\code{MockShinySession$onRestored()}}
|
||||
\item \href{#method-exportTestValues}{\code{MockShinySession$exportTestValues()}}
|
||||
\item \href{#method-getTestSnapshotUrl}{\code{MockShinySession$getTestSnapshotUrl()}}
|
||||
\item \href{#method-ns}{\code{MockShinySession$ns()}}
|
||||
\item \href{#method-flushReact}{\code{MockShinySession$flushReact()}}
|
||||
\item \href{#method-makeScope}{\code{MockShinySession$makeScope()}}
|
||||
\item \href{#method-clone}{\code{MockShinySession$clone()}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-reactlog"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-reactlog}{}}}
|
||||
\subsection{Method \code{reactlog()}}{
|
||||
No-op
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$reactlog(logEntry)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{logEntry}}{Not used}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-incrementBusyCount"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-incrementBusyCount}{}}}
|
||||
\subsection{Method \code{incrementBusyCount()}}{
|
||||
No-op
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$incrementBusyCount()}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-new"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-new}{}}}
|
||||
\subsection{Method \code{new()}}{
|
||||
Create a new MockShinySession
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$new()}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-onFlush"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-onFlush}{}}}
|
||||
\subsection{Method \code{onFlush()}}{
|
||||
Define a callback to be invoked before a reactive flush
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$onFlush(fun, once = TRUE)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{fun}}{The function to invoke}
|
||||
|
||||
\item{\code{once}}{If \code{TRUE}, will only run once. Otherwise, will run every time reactives are flushed.}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-onFlushed"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-onFlushed}{}}}
|
||||
\subsection{Method \code{onFlushed()}}{
|
||||
Define a callback to be invoked after a reactive flush
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$onFlushed(fun, once = TRUE)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{fun}}{The function to invoke}
|
||||
|
||||
\item{\code{once}}{If \code{TRUE}, will only run once. Otherwise, will run every time reactives are flushed.}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-onEnded"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-onEnded}{}}}
|
||||
\subsection{Method \code{onEnded()}}{
|
||||
Define a callback to be invoked when the session ends
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$onEnded(sessionEndedCallback)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{sessionEndedCallback}}{The callback to invoke when the session has ended.}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-isEnded"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-isEnded}{}}}
|
||||
\subsection{Method \code{isEnded()}}{
|
||||
Returns \code{FALSE} if the session has not yet been closed
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$isEnded()}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-isClosed"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-isClosed}{}}}
|
||||
\subsection{Method \code{isClosed()}}{
|
||||
Returns \code{FALSE} if the session has not yet been closed
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$isClosed()}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-close"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-close}{}}}
|
||||
\subsection{Method \code{close()}}{
|
||||
Closes the session
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$close()}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-cycleStartAction"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-cycleStartAction}{}}}
|
||||
\subsection{Method \code{cycleStartAction()}}{
|
||||
Unsophisticated mock implementation that merely invokes
|
||||
the given callback immediately.
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$cycleStartAction(callback)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{callback}}{The callback ato be invoked.}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-fileUrl"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-fileUrl}{}}}
|
||||
\subsection{Method \code{fileUrl()}}{
|
||||
Base64-encode the given file. Needed for image rendering.
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$fileUrl(name, file, contentType = "application/octet-stream")}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{name}}{Not used}
|
||||
|
||||
\item{\code{file}}{The file to be encoded}
|
||||
|
||||
\item{\code{contentType}}{The content type of the base64-encoded string}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-setInputs"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-setInputs}{}}}
|
||||
\subsection{Method \code{setInputs()}}{
|
||||
Sets reactive values associated with the \code{session$inputs} object
|
||||
and flushes the reactives.
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$setInputs(...)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{...}}{The inputs to set.}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
\subsection{Examples}{
|
||||
\if{html}{\out{<div class="r example copy">}}
|
||||
\preformatted{s <- MockShinySession$new()
|
||||
s$setInputs(x=1, y=2)
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-.scheduleTask"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-.scheduleTask}{}}}
|
||||
\subsection{Method \code{.scheduleTask()}}{
|
||||
An internal method which shouldn't be used by others.
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$.scheduleTask(millis, callback)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{millis}}{The number of milliseconds on which to schedule a callback}
|
||||
|
||||
\item{\code{callback}}{The function to schedule}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-elapse"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-elapse}{}}}
|
||||
\subsection{Method \code{elapse()}}{
|
||||
Simulate the passing of time by the given number of milliseconds.
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$elapse(millis)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{millis}}{The number of milliseconds to advance time.}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-.now"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-.now}{}}}
|
||||
\subsection{Method \code{.now()}}{
|
||||
An internal method which shouldn't be used by others.
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$.now()}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-defineOutput"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-defineOutput}{}}}
|
||||
\subsection{Method \code{defineOutput()}}{
|
||||
An internal method which shouldn't be used by others.
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$defineOutput(name, func, label)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{name}}{The name of the output}
|
||||
|
||||
\item{\code{func}}{The render definition}
|
||||
|
||||
\item{\code{label}}{Not used}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-getOutput"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-getOutput}{}}}
|
||||
\subsection{Method \code{getOutput()}}{
|
||||
An internal method which shouldn't be used by others.
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$getOutput(name)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{name}}{The name of the output}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-registerDataObj"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-registerDataObj}{}}}
|
||||
\subsection{Method \code{registerDataObj()}}{
|
||||
No-op
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$registerDataObj(name, data, filterFunc)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{name}}{Not used}
|
||||
|
||||
\item{\code{data}}{Not used}
|
||||
|
||||
\item{\code{filterFunc}}{Not used}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-allowReconnect"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-allowReconnect}{}}}
|
||||
\subsection{Method \code{allowReconnect()}}{
|
||||
No-op
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$allowReconnect(value)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{value}}{Not used}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-reload"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-reload}{}}}
|
||||
\subsection{Method \code{reload()}}{
|
||||
No-op
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$reload()}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-resetBrush"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-resetBrush}{}}}
|
||||
\subsection{Method \code{resetBrush()}}{
|
||||
No-op
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$resetBrush(brushId)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{brushId}}{Not used}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-sendCustomMessage"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-sendCustomMessage}{}}}
|
||||
\subsection{Method \code{sendCustomMessage()}}{
|
||||
No-op
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$sendCustomMessage(type, message)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{type}}{Not used}
|
||||
|
||||
\item{\code{message}}{Not used}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-sendBinaryMessage"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-sendBinaryMessage}{}}}
|
||||
\subsection{Method \code{sendBinaryMessage()}}{
|
||||
No-op
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$sendBinaryMessage(type, message)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{type}}{Not used}
|
||||
|
||||
\item{\code{message}}{Not used}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-sendInputMessage"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-sendInputMessage}{}}}
|
||||
\subsection{Method \code{sendInputMessage()}}{
|
||||
No-op
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$sendInputMessage(inputId, message)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{inputId}}{Not used}
|
||||
|
||||
\item{\code{message}}{Not used}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-setBookmarkExclude"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-setBookmarkExclude}{}}}
|
||||
\subsection{Method \code{setBookmarkExclude()}}{
|
||||
No-op
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$setBookmarkExclude(names)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{names}}{Not used}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-getBookmarkExclude"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-getBookmarkExclude}{}}}
|
||||
\subsection{Method \code{getBookmarkExclude()}}{
|
||||
No-op
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$getBookmarkExclude()}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-onBookmark"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-onBookmark}{}}}
|
||||
\subsection{Method \code{onBookmark()}}{
|
||||
No-op
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$onBookmark(fun)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{fun}}{Not used}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-onBookmarked"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-onBookmarked}{}}}
|
||||
\subsection{Method \code{onBookmarked()}}{
|
||||
No-op
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$onBookmarked(fun)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{fun}}{Not used}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-doBookmark"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-doBookmark}{}}}
|
||||
\subsection{Method \code{doBookmark()}}{
|
||||
No-op
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$doBookmark()}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-onRestore"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-onRestore}{}}}
|
||||
\subsection{Method \code{onRestore()}}{
|
||||
No-op
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$onRestore(fun)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{fun}}{Not used}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-onRestored"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-onRestored}{}}}
|
||||
\subsection{Method \code{onRestored()}}{
|
||||
No-op
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$onRestored(fun)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{fun}}{Not used}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-exportTestValues"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-exportTestValues}{}}}
|
||||
\subsection{Method \code{exportTestValues()}}{
|
||||
No-op
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$exportTestValues()}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-getTestSnapshotUrl"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-getTestSnapshotUrl}{}}}
|
||||
\subsection{Method \code{getTestSnapshotUrl()}}{
|
||||
No-op
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$getTestSnapshotUrl(
|
||||
input = TRUE,
|
||||
output = TRUE,
|
||||
export = TRUE,
|
||||
format = "json"
|
||||
)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{input}}{Not used}
|
||||
|
||||
\item{\code{output}}{Not used}
|
||||
|
||||
\item{\code{export}}{Not used}
|
||||
|
||||
\item{\code{format}}{Not used}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-ns"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-ns}{}}}
|
||||
\subsection{Method \code{ns()}}{
|
||||
Returns the given id prefixed by \verb{mock-session-}.
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$ns(id)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{id}}{The id to modify.}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-flushReact"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-flushReact}{}}}
|
||||
\subsection{Method \code{flushReact()}}{
|
||||
Trigger a reactive flush right now.
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$flushReact()}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-makeScope"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-makeScope}{}}}
|
||||
\subsection{Method \code{makeScope()}}{
|
||||
Create and return a namespace-specific session proxy.
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$makeScope(namespace)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{namespace}}{Character vector indicating a namespace.}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-clone"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-clone}{}}}
|
||||
\subsection{Method \code{clone()}}{
|
||||
The objects of this class are cloneable with this method.
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$clone(deep = FALSE)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{deep}}{Whether to make a deep clone.}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,9 @@
|
||||
\alias{NS}
|
||||
\alias{ns.sep}
|
||||
\title{Namespaced IDs for inputs/outputs}
|
||||
\format{An object of class \code{character} of length 1.}
|
||||
\format{
|
||||
An object of class \code{character} of length 1.
|
||||
}
|
||||
\usage{
|
||||
NS(namespace, id = NULL)
|
||||
|
||||
|
||||
224
man/Progress.Rd
224
man/Progress.Rd
@@ -1,47 +1,16 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/progress.R
|
||||
\docType{data}
|
||||
\name{Progress}
|
||||
\alias{Progress}
|
||||
\title{Reporting progress (object-oriented API)}
|
||||
\arguments{
|
||||
\item{session}{The Shiny session object, as provided by
|
||||
\code{shinyServer} to the server function.}
|
||||
|
||||
\item{min}{The value that represents the starting point of the
|
||||
progress bar. Must be less than \code{max}.}
|
||||
|
||||
\item{max}{The value that represents the end of the progress bar.
|
||||
Must be greater than \code{min}.}
|
||||
|
||||
\item{message}{A single-element character vector; the message to be
|
||||
displayed to the user, or \code{NULL} to hide the current message
|
||||
(if any).}
|
||||
|
||||
\item{detail}{A single-element character vector; the detail message
|
||||
to be displayed to the user, or \code{NULL} to hide the current
|
||||
detail message (if any). The detail message will be shown with a
|
||||
de-emphasized appearance relative to \code{message}.}
|
||||
|
||||
\item{value}{A numeric value at which to set
|
||||
the progress bar, relative to \code{min} and \code{max}.}
|
||||
|
||||
\item{style}{Progress display style. If \code{"notification"} (the default),
|
||||
the progress indicator will show using Shiny's notification API. If
|
||||
\code{"old"}, use the same HTML and CSS used in Shiny 0.13.2 and below
|
||||
(this is for backward-compatibility).}
|
||||
|
||||
\item{amount}{Single-element numeric vector; the value at which to set
|
||||
the progress bar, relative to \code{min} and \code{max}.
|
||||
\code{NULL} hides the progress bar, if it is currently visible.}
|
||||
|
||||
\item{amount}{For the \code{inc()} method, a numeric value to increment the
|
||||
progress bar.}
|
||||
}
|
||||
\description{
|
||||
Reports progress to the user during long-running operations.
|
||||
Reporting progress (object-oriented API)
|
||||
|
||||
Reporting progress (object-oriented API)
|
||||
}
|
||||
\details{
|
||||
Reports progress to the user during long-running operations.
|
||||
|
||||
This package exposes two distinct programming APIs for working with
|
||||
progress. \code{\link[=withProgress]{withProgress()}} and \code{\link[=setProgress]{setProgress()}}
|
||||
together provide a simple function-based interface, while the
|
||||
@@ -59,26 +28,6 @@ CSS), you can use \code{style="old"} each time you call
|
||||
\code{Progress$new} is called, you can instead call
|
||||
\code{\link[=shinyOptions]{shinyOptions(progress.style="old")}} just once, inside the server
|
||||
function.
|
||||
|
||||
\strong{Methods}
|
||||
\describe{
|
||||
\item{\code{initialize(session, min = 0, max = 1)}}{
|
||||
Creates a new progress panel (but does not display it).
|
||||
}
|
||||
\item{\code{set(value = NULL, message = NULL, detail = NULL)}}{
|
||||
Updates the progress panel. When called the first time, the
|
||||
progress panel is displayed.
|
||||
}
|
||||
\item{\code{inc(amount = 0.1, message = NULL, detail = NULL)}}{
|
||||
Like \code{set}, this updates the progress panel. The difference is
|
||||
that \code{inc} increases the progress bar by \code{amount}, instead
|
||||
of setting it to a specific value.
|
||||
}
|
||||
\item{\code{close()}}{
|
||||
Removes the progress panel. Future calls to \code{set} and
|
||||
\code{close} will be ignored.
|
||||
}
|
||||
}
|
||||
}
|
||||
\examples{
|
||||
## Only run examples in interactive R sessions
|
||||
@@ -110,4 +59,165 @@ shinyApp(ui, server)
|
||||
\seealso{
|
||||
\code{\link[=withProgress]{withProgress()}}
|
||||
}
|
||||
\keyword{datasets}
|
||||
\section{Methods}{
|
||||
\subsection{Public methods}{
|
||||
\itemize{
|
||||
\item \href{#method-new}{\code{Progress$new()}}
|
||||
\item \href{#method-set}{\code{Progress$set()}}
|
||||
\item \href{#method-inc}{\code{Progress$inc()}}
|
||||
\item \href{#method-getMin}{\code{Progress$getMin()}}
|
||||
\item \href{#method-getMax}{\code{Progress$getMax()}}
|
||||
\item \href{#method-getValue}{\code{Progress$getValue()}}
|
||||
\item \href{#method-close}{\code{Progress$close()}}
|
||||
\item \href{#method-clone}{\code{Progress$clone()}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-new"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-new}{}}}
|
||||
\subsection{Method \code{new()}}{
|
||||
Creates a new progress panel (but does not display it).
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{Progress$new(
|
||||
session = getDefaultReactiveDomain(),
|
||||
min = 0,
|
||||
max = 1,
|
||||
style = getShinyOption("progress.style", default = "notification")
|
||||
)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{session}}{The Shiny session object, as provided by \code{shinyServer} to
|
||||
the server function.}
|
||||
|
||||
\item{\code{min}}{The value that represents the starting point of the progress
|
||||
bar. Must be less than \code{max}.}
|
||||
|
||||
\item{\code{max}}{The value that represents the end of the progress bar. Must be
|
||||
greater than \code{min}.}
|
||||
|
||||
\item{\code{style}}{Progress display style. If \code{"notification"} (the default),
|
||||
the progress indicator will show using Shiny's notification API. If
|
||||
\code{"old"}, use the same HTML and CSS used in Shiny 0.13.2 and below (this
|
||||
is for backward-compatibility).}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-set"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-set}{}}}
|
||||
\subsection{Method \code{set()}}{
|
||||
Updates the progress panel. When called the first time, the
|
||||
progress panel is displayed.
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{Progress$set(value = NULL, message = NULL, detail = NULL)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{value}}{Single-element numeric vector; the value at which to set the
|
||||
progress bar, relative to \code{min} and \code{max}. \code{NULL} hides the progress
|
||||
bar, if it is currently visible.}
|
||||
|
||||
\item{\code{message}}{A single-element character vector; the message to be
|
||||
displayed to the user, or \code{NULL} to hide the current message (if any).}
|
||||
|
||||
\item{\code{detail}}{A single-element character vector; the detail message to be
|
||||
displayed to the user, or \code{NULL} to hide the current detail message (if
|
||||
any). The detail message will be shown with a de-emphasized appearance
|
||||
relative to \code{message}.}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-inc"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-inc}{}}}
|
||||
\subsection{Method \code{inc()}}{
|
||||
Like \code{set}, this updates the progress panel. The difference
|
||||
is that \code{inc} increases the progress bar by \code{amount}, instead of
|
||||
setting it to a specific value.
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{Progress$inc(amount = 0.1, message = NULL, detail = NULL)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{amount}}{For the \code{inc()} method, a numeric value to increment the
|
||||
progress bar.}
|
||||
|
||||
\item{\code{message}}{A single-element character vector; the message to be
|
||||
displayed to the user, or \code{NULL} to hide the current message (if any).}
|
||||
|
||||
\item{\code{detail}}{A single-element character vector; the detail message to be
|
||||
displayed to the user, or \code{NULL} to hide the current detail message (if
|
||||
any). The detail message will be shown with a de-emphasized appearance
|
||||
relative to \code{message}.}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-getMin"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-getMin}{}}}
|
||||
\subsection{Method \code{getMin()}}{
|
||||
Returns the minimum value.
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{Progress$getMin()}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-getMax"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-getMax}{}}}
|
||||
\subsection{Method \code{getMax()}}{
|
||||
Returns the maximum value.
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{Progress$getMax()}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-getValue"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-getValue}{}}}
|
||||
\subsection{Method \code{getValue()}}{
|
||||
Returns the current value.
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{Progress$getValue()}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-close"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-close}{}}}
|
||||
\subsection{Method \code{close()}}{
|
||||
Removes the progress panel. Future calls to \code{set} and
|
||||
\code{close} will be ignored.
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{Progress$close()}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
}
|
||||
\if{html}{\out{<hr>}}
|
||||
\if{html}{\out{<a id="method-clone"></a>}}
|
||||
\if{latex}{\out{\hypertarget{method-clone}{}}}
|
||||
\subsection{Method \code{clone()}}{
|
||||
The objects of this class are cloneable with this method.
|
||||
\subsection{Usage}{
|
||||
\if{html}{\out{<div class="r">}}\preformatted{Progress$clone(deep = FALSE)}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\subsection{Arguments}{
|
||||
\if{html}{\out{<div class="arguments">}}
|
||||
\describe{
|
||||
\item{\code{deep}}{Whether to make a deep clone.}
|
||||
}
|
||||
\if{html}{\out{</div>}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,30 @@
|
||||
\alias{fixedPanel}
|
||||
\title{Panel with absolute positioning}
|
||||
\usage{
|
||||
absolutePanel(..., top = NULL, left = NULL, right = NULL,
|
||||
bottom = NULL, width = NULL, height = NULL, draggable = FALSE,
|
||||
fixed = FALSE, cursor = c("auto", "move", "default", "inherit"))
|
||||
absolutePanel(
|
||||
...,
|
||||
top = NULL,
|
||||
left = NULL,
|
||||
right = NULL,
|
||||
bottom = NULL,
|
||||
width = NULL,
|
||||
height = NULL,
|
||||
draggable = FALSE,
|
||||
fixed = FALSE,
|
||||
cursor = c("auto", "move", "default", "inherit")
|
||||
)
|
||||
|
||||
fixedPanel(..., top = NULL, left = NULL, right = NULL,
|
||||
bottom = NULL, width = NULL, height = NULL, draggable = FALSE,
|
||||
cursor = c("auto", "move", "default", "inherit"))
|
||||
fixedPanel(
|
||||
...,
|
||||
top = NULL,
|
||||
left = NULL,
|
||||
right = NULL,
|
||||
bottom = NULL,
|
||||
width = NULL,
|
||||
height = NULL,
|
||||
draggable = FALSE,
|
||||
cursor = c("auto", "move", "default", "inherit")
|
||||
)
|
||||
}
|
||||
\arguments{
|
||||
\item{...}{Attributes (named arguments) or children (unnamed arguments) that
|
||||
@@ -53,7 +70,7 @@ An HTML element or list of elements.
|
||||
Creates a panel whose contents are absolutely positioned.
|
||||
}
|
||||
\details{
|
||||
The \code{absolutePanel} function creates a \code{<div>} tag whose CSS
|
||||
The \code{absolutePanel} function creates a \verb{<div>} tag whose CSS
|
||||
position is set to \code{absolute} (or fixed if \code{fixed = TRUE}). The way
|
||||
absolute positioning works in HTML is that absolute coordinates are specified
|
||||
relative to its nearest parent element whose position is not set to
|
||||
|
||||
@@ -26,6 +26,17 @@ see \code{\link[=validateCssUnit]{validateCssUnit()}}.}
|
||||
Creates an action button or link whose value is initially zero, and increments by one
|
||||
each time it is pressed.
|
||||
}
|
||||
\section{Server value}{
|
||||
|
||||
An integer of class \code{"shinyActionButtonValue"}. This class differs from
|
||||
ordinary integers in that a value of 0 is considered "falsy".
|
||||
This implies two things:
|
||||
\itemize{
|
||||
\item Event handlers (e.g., \code{\link[=observeEvent]{observeEvent()}}, \code{\link[=eventReactive]{eventReactive()}}) won't execute on initial load.
|
||||
\item Input validation (e.g., \code{\link[=req]{req()}}, \code{\link[=need]{need()}}) will fail on initial load.
|
||||
}
|
||||
}
|
||||
|
||||
\examples{
|
||||
## Only run examples in interactive R sessions
|
||||
if (interactive()) {
|
||||
@@ -56,13 +67,20 @@ shinyApp(ui, server)
|
||||
\seealso{
|
||||
\code{\link[=observeEvent]{observeEvent()}} and \code{\link[=eventReactive]{eventReactive()}}
|
||||
|
||||
Other input elements: \code{\link{checkboxGroupInput}},
|
||||
\code{\link{checkboxInput}}, \code{\link{dateInput}},
|
||||
\code{\link{dateRangeInput}}, \code{\link{fileInput}},
|
||||
\code{\link{numericInput}}, \code{\link{passwordInput}},
|
||||
\code{\link{radioButtons}}, \code{\link{selectInput}},
|
||||
\code{\link{sliderInput}}, \code{\link{submitButton}},
|
||||
\code{\link{textAreaInput}}, \code{\link{textInput}},
|
||||
\code{\link{varSelectInput}}
|
||||
Other input elements:
|
||||
\code{\link{checkboxGroupInput}()},
|
||||
\code{\link{checkboxInput}()},
|
||||
\code{\link{dateInput}()},
|
||||
\code{\link{dateRangeInput}()},
|
||||
\code{\link{fileInput}()},
|
||||
\code{\link{numericInput}()},
|
||||
\code{\link{passwordInput}()},
|
||||
\code{\link{radioButtons}()},
|
||||
\code{\link{selectInput}()},
|
||||
\code{\link{sliderInput}()},
|
||||
\code{\link{submitButton}()},
|
||||
\code{\link{textAreaInput}()},
|
||||
\code{\link{textInput}()},
|
||||
\code{\link{varSelectInput}()}
|
||||
}
|
||||
\concept{input elements}
|
||||
|
||||
@@ -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()}}
|
||||
}
|
||||
@@ -4,10 +4,13 @@
|
||||
\alias{bookmarkButton}
|
||||
\title{Create a button for bookmarking/sharing}
|
||||
\usage{
|
||||
bookmarkButton(label = "Bookmark...", icon = shiny::icon("link", lib =
|
||||
"glyphicon"),
|
||||
bookmarkButton(
|
||||
label = "Bookmark...",
|
||||
icon = shiny::icon("link", lib = "glyphicon"),
|
||||
title = "Bookmark this application's state and get a URL for sharing.",
|
||||
..., id = "._bookmark_")
|
||||
...,
|
||||
id = "._bookmark_"
|
||||
)
|
||||
}
|
||||
\arguments{
|
||||
\item{label}{The contents of the button or link--usually a text label, but
|
||||
|
||||
@@ -4,9 +4,17 @@
|
||||
\alias{brushOpts}
|
||||
\title{Create an object representing brushing options}
|
||||
\usage{
|
||||
brushOpts(id = NULL, fill = "#9cf", stroke = "#036",
|
||||
opacity = 0.25, delay = 300, delayType = c("debounce", "throttle"),
|
||||
clip = TRUE, direction = c("xy", "x", "y"), resetOnNew = FALSE)
|
||||
brushOpts(
|
||||
id = NULL,
|
||||
fill = "#9cf",
|
||||
stroke = "#036",
|
||||
opacity = 0.25,
|
||||
delay = 300,
|
||||
delayType = c("debounce", "throttle"),
|
||||
clip = TRUE,
|
||||
direction = c("xy", "x", "y"),
|
||||
resetOnNew = FALSE
|
||||
)
|
||||
}
|
||||
\arguments{
|
||||
\item{id}{Input value name. For example, if the value is \code{"plot_brush"},
|
||||
|
||||
@@ -4,8 +4,15 @@
|
||||
\alias{brushedPoints}
|
||||
\title{Find rows of data that are selected by a brush}
|
||||
\usage{
|
||||
brushedPoints(df, brush, xvar = NULL, yvar = NULL, panelvar1 = NULL,
|
||||
panelvar2 = NULL, allRows = FALSE)
|
||||
brushedPoints(
|
||||
df,
|
||||
brush,
|
||||
xvar = NULL,
|
||||
yvar = NULL,
|
||||
panelvar1 = NULL,
|
||||
panelvar2 = NULL,
|
||||
allRows = FALSE
|
||||
)
|
||||
}
|
||||
\arguments{
|
||||
\item{df}{A data frame from which to select rows.}
|
||||
|
||||
@@ -1,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,31 +0,0 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/modules.R
|
||||
\name{callModule}
|
||||
\alias{callModule}
|
||||
\title{Invoke a Shiny module}
|
||||
\usage{
|
||||
callModule(module, id, ..., session = getDefaultReactiveDomain())
|
||||
}
|
||||
\arguments{
|
||||
\item{module}{A Shiny module server function}
|
||||
|
||||
\item{id}{An ID string that corresponds with the ID used to call the module's
|
||||
UI function}
|
||||
|
||||
\item{...}{Additional parameters to pass to module server function}
|
||||
|
||||
\item{session}{Session from which to make a child scope (the default should
|
||||
almost always be used)}
|
||||
}
|
||||
\value{
|
||||
The return value, if any, from executing the module server function
|
||||
}
|
||||
\description{
|
||||
Shiny's module feature lets you break complicated UI and server logic into
|
||||
smaller, self-contained pieces. Compared to large monolithic Shiny apps,
|
||||
modules are easier to reuse and easier to reason about. See the article at
|
||||
\url{http://shiny.rstudio.com/articles/modules.html} to learn more.
|
||||
}
|
||||
\seealso{
|
||||
\url{http://shiny.rstudio.com/articles/modules.html}
|
||||
}
|
||||
@@ -4,9 +4,16 @@
|
||||
\alias{checkboxGroupInput}
|
||||
\title{Checkbox Group Input Control}
|
||||
\usage{
|
||||
checkboxGroupInput(inputId, label, choices = NULL, selected = NULL,
|
||||
inline = FALSE, width = NULL, choiceNames = NULL,
|
||||
choiceValues = NULL)
|
||||
checkboxGroupInput(
|
||||
inputId,
|
||||
label,
|
||||
choices = NULL,
|
||||
selected = NULL,
|
||||
inline = FALSE,
|
||||
width = NULL,
|
||||
choiceNames = NULL,
|
||||
choiceValues = NULL
|
||||
)
|
||||
}
|
||||
\arguments{
|
||||
\item{inputId}{The \code{input} slot that will be used to access the value.}
|
||||
@@ -44,6 +51,11 @@ Create a group of checkboxes that can be used to toggle multiple choices
|
||||
independently. The server will receive the input as a character vector of the
|
||||
selected values.
|
||||
}
|
||||
\section{Server value}{
|
||||
|
||||
Character vector of values corresponding to the boxes that are checked.
|
||||
}
|
||||
|
||||
\examples{
|
||||
## Only run examples in interactive R sessions
|
||||
if (interactive()) {
|
||||
@@ -88,13 +100,20 @@ shinyApp(ui, server)
|
||||
\seealso{
|
||||
\code{\link[=checkboxInput]{checkboxInput()}}, \code{\link[=updateCheckboxGroupInput]{updateCheckboxGroupInput()}}
|
||||
|
||||
Other input elements: \code{\link{actionButton}},
|
||||
\code{\link{checkboxInput}}, \code{\link{dateInput}},
|
||||
\code{\link{dateRangeInput}}, \code{\link{fileInput}},
|
||||
\code{\link{numericInput}}, \code{\link{passwordInput}},
|
||||
\code{\link{radioButtons}}, \code{\link{selectInput}},
|
||||
\code{\link{sliderInput}}, \code{\link{submitButton}},
|
||||
\code{\link{textAreaInput}}, \code{\link{textInput}},
|
||||
\code{\link{varSelectInput}}
|
||||
Other input elements:
|
||||
\code{\link{actionButton}()},
|
||||
\code{\link{checkboxInput}()},
|
||||
\code{\link{dateInput}()},
|
||||
\code{\link{dateRangeInput}()},
|
||||
\code{\link{fileInput}()},
|
||||
\code{\link{numericInput}()},
|
||||
\code{\link{passwordInput}()},
|
||||
\code{\link{radioButtons}()},
|
||||
\code{\link{selectInput}()},
|
||||
\code{\link{sliderInput}()},
|
||||
\code{\link{submitButton}()},
|
||||
\code{\link{textAreaInput}()},
|
||||
\code{\link{textInput}()},
|
||||
\code{\link{varSelectInput}()}
|
||||
}
|
||||
\concept{input elements}
|
||||
|
||||
@@ -22,6 +22,11 @@ A checkbox control that can be added to a UI definition.
|
||||
\description{
|
||||
Create a checkbox that can be used to specify logical values.
|
||||
}
|
||||
\section{Server value}{
|
||||
|
||||
\code{TRUE} if checked, \code{FALSE} otherwise.
|
||||
}
|
||||
|
||||
\examples{
|
||||
## Only run examples in interactive R sessions
|
||||
if (interactive()) {
|
||||
@@ -35,17 +40,25 @@ server <- function(input, output) {
|
||||
}
|
||||
shinyApp(ui, server)
|
||||
}
|
||||
|
||||
}
|
||||
\seealso{
|
||||
\code{\link[=checkboxGroupInput]{checkboxGroupInput()}}, \code{\link[=updateCheckboxInput]{updateCheckboxInput()}}
|
||||
|
||||
Other input elements: \code{\link{actionButton}},
|
||||
\code{\link{checkboxGroupInput}},
|
||||
\code{\link{dateInput}}, \code{\link{dateRangeInput}},
|
||||
\code{\link{fileInput}}, \code{\link{numericInput}},
|
||||
\code{\link{passwordInput}}, \code{\link{radioButtons}},
|
||||
\code{\link{selectInput}}, \code{\link{sliderInput}},
|
||||
\code{\link{submitButton}}, \code{\link{textAreaInput}},
|
||||
\code{\link{textInput}}, \code{\link{varSelectInput}}
|
||||
Other input elements:
|
||||
\code{\link{actionButton}()},
|
||||
\code{\link{checkboxGroupInput}()},
|
||||
\code{\link{dateInput}()},
|
||||
\code{\link{dateRangeInput}()},
|
||||
\code{\link{fileInput}()},
|
||||
\code{\link{numericInput}()},
|
||||
\code{\link{passwordInput}()},
|
||||
\code{\link{radioButtons}()},
|
||||
\code{\link{selectInput}()},
|
||||
\code{\link{sliderInput}()},
|
||||
\code{\link{submitButton}()},
|
||||
\code{\link{textAreaInput}()},
|
||||
\code{\link{textInput}()},
|
||||
\code{\link{varSelectInput}()}
|
||||
}
|
||||
\concept{input elements}
|
||||
|
||||
@@ -4,8 +4,12 @@
|
||||
\alias{createRenderFunction}
|
||||
\title{Implement render functions}
|
||||
\usage{
|
||||
createRenderFunction(func, transform = function(value, session, name,
|
||||
...) value, outputFunc = NULL, outputArgs = NULL)
|
||||
createRenderFunction(
|
||||
func,
|
||||
transform = function(value, session, name, ...) value,
|
||||
outputFunc = NULL,
|
||||
outputArgs = NULL
|
||||
)
|
||||
}
|
||||
\arguments{
|
||||
\item{func}{A function without parameters, that returns user data. If the
|
||||
|
||||
@@ -4,10 +4,21 @@
|
||||
\alias{dateInput}
|
||||
\title{Create date input}
|
||||
\usage{
|
||||
dateInput(inputId, label, value = NULL, min = NULL, max = NULL,
|
||||
format = "yyyy-mm-dd", startview = "month", weekstart = 0,
|
||||
language = "en", width = NULL, autoclose = TRUE,
|
||||
datesdisabled = NULL, daysofweekdisabled = NULL)
|
||||
dateInput(
|
||||
inputId,
|
||||
label,
|
||||
value = NULL,
|
||||
min = NULL,
|
||||
max = NULL,
|
||||
format = "yyyy-mm-dd",
|
||||
startview = "month",
|
||||
weekstart = 0,
|
||||
language = "en",
|
||||
width = NULL,
|
||||
autoclose = TRUE,
|
||||
datesdisabled = NULL,
|
||||
daysofweekdisabled = NULL
|
||||
)
|
||||
}
|
||||
\arguments{
|
||||
\item{inputId}{The \code{input} slot that will be used to access the value.}
|
||||
@@ -75,6 +86,11 @@ the browser. It allows the following values:
|
||||
\item \code{DD} Full weekday name
|
||||
}
|
||||
}
|
||||
\section{Server value}{
|
||||
|
||||
A \link{Date} vector of length 1.
|
||||
}
|
||||
|
||||
\examples{
|
||||
## Only run examples in interactive R sessions
|
||||
if (interactive()) {
|
||||
@@ -110,18 +126,25 @@ ui <- fluidPage(
|
||||
|
||||
shinyApp(ui, server = function(input, output) { })
|
||||
}
|
||||
|
||||
}
|
||||
\seealso{
|
||||
\code{\link[=dateRangeInput]{dateRangeInput()}}, \code{\link[=updateDateInput]{updateDateInput()}}
|
||||
|
||||
Other input elements: \code{\link{actionButton}},
|
||||
\code{\link{checkboxGroupInput}},
|
||||
\code{\link{checkboxInput}},
|
||||
\code{\link{dateRangeInput}}, \code{\link{fileInput}},
|
||||
\code{\link{numericInput}}, \code{\link{passwordInput}},
|
||||
\code{\link{radioButtons}}, \code{\link{selectInput}},
|
||||
\code{\link{sliderInput}}, \code{\link{submitButton}},
|
||||
\code{\link{textAreaInput}}, \code{\link{textInput}},
|
||||
\code{\link{varSelectInput}}
|
||||
Other input elements:
|
||||
\code{\link{actionButton}()},
|
||||
\code{\link{checkboxGroupInput}()},
|
||||
\code{\link{checkboxInput}()},
|
||||
\code{\link{dateRangeInput}()},
|
||||
\code{\link{fileInput}()},
|
||||
\code{\link{numericInput}()},
|
||||
\code{\link{passwordInput}()},
|
||||
\code{\link{radioButtons}()},
|
||||
\code{\link{selectInput}()},
|
||||
\code{\link{sliderInput}()},
|
||||
\code{\link{submitButton}()},
|
||||
\code{\link{textAreaInput}()},
|
||||
\code{\link{textInput}()},
|
||||
\code{\link{varSelectInput}()}
|
||||
}
|
||||
\concept{input elements}
|
||||
|
||||
@@ -4,10 +4,21 @@
|
||||
\alias{dateRangeInput}
|
||||
\title{Create date range input}
|
||||
\usage{
|
||||
dateRangeInput(inputId, label, start = NULL, end = NULL, min = NULL,
|
||||
max = NULL, format = "yyyy-mm-dd", startview = "month",
|
||||
weekstart = 0, language = "en", separator = " to ", width = NULL,
|
||||
autoclose = TRUE)
|
||||
dateRangeInput(
|
||||
inputId,
|
||||
label,
|
||||
start = NULL,
|
||||
end = NULL,
|
||||
min = NULL,
|
||||
max = NULL,
|
||||
format = "yyyy-mm-dd",
|
||||
startview = "month",
|
||||
weekstart = 0,
|
||||
language = "en",
|
||||
separator = " to ",
|
||||
width = NULL,
|
||||
autoclose = TRUE
|
||||
)
|
||||
}
|
||||
\arguments{
|
||||
\item{inputId}{The \code{input} slot that will be used to access the value.}
|
||||
@@ -75,6 +86,11 @@ the browser. It allows the following values:
|
||||
\item \code{DD} Full weekday name
|
||||
}
|
||||
}
|
||||
\section{Server value}{
|
||||
|
||||
A \link{Date} vector of length 2.
|
||||
}
|
||||
|
||||
\examples{
|
||||
## Only run examples in interactive R sessions
|
||||
if (interactive()) {
|
||||
@@ -114,17 +130,25 @@ ui <- fluidPage(
|
||||
|
||||
shinyApp(ui, server = function(input, output) { })
|
||||
}
|
||||
|
||||
}
|
||||
\seealso{
|
||||
\code{\link[=dateInput]{dateInput()}}, \code{\link[=updateDateRangeInput]{updateDateRangeInput()}}
|
||||
|
||||
Other input elements: \code{\link{actionButton}},
|
||||
\code{\link{checkboxGroupInput}},
|
||||
\code{\link{checkboxInput}}, \code{\link{dateInput}},
|
||||
\code{\link{fileInput}}, \code{\link{numericInput}},
|
||||
\code{\link{passwordInput}}, \code{\link{radioButtons}},
|
||||
\code{\link{selectInput}}, \code{\link{sliderInput}},
|
||||
\code{\link{submitButton}}, \code{\link{textAreaInput}},
|
||||
\code{\link{textInput}}, \code{\link{varSelectInput}}
|
||||
Other input elements:
|
||||
\code{\link{actionButton}()},
|
||||
\code{\link{checkboxGroupInput}()},
|
||||
\code{\link{checkboxInput}()},
|
||||
\code{\link{dateInput}()},
|
||||
\code{\link{fileInput}()},
|
||||
\code{\link{numericInput}()},
|
||||
\code{\link{passwordInput}()},
|
||||
\code{\link{radioButtons}()},
|
||||
\code{\link{selectInput}()},
|
||||
\code{\link{sliderInput}()},
|
||||
\code{\link{submitButton}()},
|
||||
\code{\link{textAreaInput}()},
|
||||
\code{\link{textInput}()},
|
||||
\code{\link{varSelectInput}()}
|
||||
}
|
||||
\concept{input elements}
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
\alias{throttle}
|
||||
\title{Slow down a reactive expression with debounce/throttle}
|
||||
\usage{
|
||||
debounce(r, millis, priority = 100,
|
||||
domain = getDefaultReactiveDomain())
|
||||
debounce(r, millis, priority = 100, domain = getDefaultReactiveDomain())
|
||||
|
||||
throttle(r, millis, priority = 100,
|
||||
domain = getDefaultReactiveDomain())
|
||||
throttle(r, millis, priority = 100, domain = getDefaultReactiveDomain())
|
||||
}
|
||||
\arguments{
|
||||
\item{r}{A reactive expression (that invalidates too often).}
|
||||
@@ -49,7 +47,7 @@ continually arrive from \code{r} within the time window, the debounced
|
||||
reactive will not invalidate at all. Only after the invalidations stop (or
|
||||
slow down sufficiently) will the downstream invalidation be sent.
|
||||
|
||||
\code{ooo-oo-oo---- => -----------o-}
|
||||
\verb{ooo-oo-oo---- => -----------o-}
|
||||
|
||||
(In this graphical depiction, each character represents a unit of time, and
|
||||
the time window is 3 characters.)
|
||||
@@ -61,7 +59,7 @@ continually come from \code{r} within the time window, the throttled reactive
|
||||
will invalidate regularly, at a rate equal to or slower than than the time
|
||||
window.
|
||||
|
||||
\code{ooo-oo-oo---- => o--o--o--o---}
|
||||
\verb{ooo-oo-oo---- => o--o--o--o---}
|
||||
}
|
||||
\section{Limitations}{
|
||||
|
||||
|
||||
@@ -4,9 +4,17 @@
|
||||
\alias{diskCache}
|
||||
\title{Create a disk cache object}
|
||||
\usage{
|
||||
diskCache(dir = NULL, max_size = 10 * 1024^2, max_age = Inf,
|
||||
max_n = Inf, evict = c("lru", "fifo"), destroy_on_finalize = FALSE,
|
||||
missing = key_missing(), exec_missing = FALSE, logfile = NULL)
|
||||
diskCache(
|
||||
dir = NULL,
|
||||
max_size = 10 * 1024^2,
|
||||
max_age = Inf,
|
||||
max_n = Inf,
|
||||
evict = c("lru", "fifo"),
|
||||
destroy_on_finalize = FALSE,
|
||||
missing = key_missing(),
|
||||
exec_missing = FALSE,
|
||||
logfile = NULL
|
||||
)
|
||||
}
|
||||
\arguments{
|
||||
\item{dir}{Directory to store files for the cache. If \code{NULL} (the
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
\alias{downloadHandler}
|
||||
\title{File Downloads}
|
||||
\usage{
|
||||
downloadHandler(filename, content, contentType = NA,
|
||||
outputArgs = list())
|
||||
downloadHandler(filename, content, contentType = NA, outputArgs = list())
|
||||
}
|
||||
\arguments{
|
||||
\item{filename}{A string of the filename, including extension, that the
|
||||
|
||||
@@ -4,8 +4,12 @@
|
||||
\alias{exportTestValues}
|
||||
\title{Register expressions for export in test mode}
|
||||
\usage{
|
||||
exportTestValues(..., quoted_ = FALSE, env_ = parent.frame(),
|
||||
session_ = getDefaultReactiveDomain())
|
||||
exportTestValues(
|
||||
...,
|
||||
quoted_ = FALSE,
|
||||
env_ = parent.frame(),
|
||||
session_ = getDefaultReactiveDomain()
|
||||
)
|
||||
}
|
||||
\arguments{
|
||||
\item{...}{Named arguments that are quoted or unquoted expressions that will
|
||||
@@ -62,7 +66,7 @@ shinyApp(
|
||||
})
|
||||
|
||||
output$values <- renderText({
|
||||
paste0("vals$x: ", vals$x, "\\ny: ", y())
|
||||
paste0("vals$x: ", vals$x, "\ny: ", y())
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
@@ -4,9 +4,15 @@
|
||||
\alias{fileInput}
|
||||
\title{File Upload Control}
|
||||
\usage{
|
||||
fileInput(inputId, label, multiple = FALSE, accept = NULL,
|
||||
width = NULL, buttonLabel = "Browse...",
|
||||
placeholder = "No file selected")
|
||||
fileInput(
|
||||
inputId,
|
||||
label,
|
||||
multiple = FALSE,
|
||||
accept = NULL,
|
||||
width = NULL,
|
||||
buttonLabel = "Browse...",
|
||||
placeholder = "No file selected"
|
||||
)
|
||||
}
|
||||
\arguments{
|
||||
\item{inputId}{The \code{input} slot that will be used to access the value.}
|
||||
@@ -17,8 +23,17 @@ fileInput(inputId, label, multiple = FALSE, accept = NULL,
|
||||
multiple files at once. \strong{Does not work on older browsers, including
|
||||
Internet Explorer 9 and earlier.}}
|
||||
|
||||
\item{accept}{A character vector of MIME types; gives the browser a hint of
|
||||
what kind of files the server is expecting.}
|
||||
\item{accept}{A character vector of "unique file type specifiers" which
|
||||
gives the browser a hint as to the type of file the server expects.
|
||||
Many browsers use this prevent the user from selecting an invalid file.
|
||||
|
||||
A unique file type specifier can be:
|
||||
\itemize{
|
||||
\item A case insensitive extension like \code{.csv} or \code{.rds}.
|
||||
\item A valid MIME type, like \code{text/plain} or \code{application/pdf}
|
||||
\item One of \verb{audio/*}, \verb{video/*}, or \verb{image/*} meaning any audio, video,
|
||||
or image type, respectively.
|
||||
}}
|
||||
|
||||
\item{width}{The width of the input, e.g. \code{'400px'}, or \code{'100\%'};
|
||||
see \code{\link[=validateCssUnit]{validateCssUnit()}}.}
|
||||
@@ -33,8 +48,11 @@ Create a file upload control that can be used to upload one or more files.
|
||||
}
|
||||
\details{
|
||||
Whenever a file upload completes, the corresponding input variable is set
|
||||
to a dataframe. This dataframe contains one row for each selected file, and
|
||||
the following columns:
|
||||
to a dataframe. See the \verb{Server value} section.
|
||||
}
|
||||
\section{Server value}{
|
||||
|
||||
A \code{data.frame} that contains one row for each selected file, and following columns:
|
||||
\describe{
|
||||
\item{\code{name}}{The filename provided by the web browser. This is
|
||||
\strong{not} the path to read to get at the actual data that was uploaded
|
||||
@@ -49,6 +67,7 @@ uploaded. This file may be deleted if the user performs another upload
|
||||
operation.}
|
||||
}
|
||||
}
|
||||
|
||||
\examples{
|
||||
## Only run examples in interactive R sessions
|
||||
if (interactive()) {
|
||||
@@ -56,13 +75,7 @@ if (interactive()) {
|
||||
ui <- fluidPage(
|
||||
sidebarLayout(
|
||||
sidebarPanel(
|
||||
fileInput("file1", "Choose CSV File",
|
||||
accept = c(
|
||||
"text/csv",
|
||||
"text/comma-separated-values,text/plain",
|
||||
".csv")
|
||||
),
|
||||
tags$hr(),
|
||||
fileInput("file1", "Choose CSV File", accept = ".csv"),
|
||||
checkboxInput("header", "Header", TRUE)
|
||||
),
|
||||
mainPanel(
|
||||
@@ -73,31 +86,35 @@ ui <- fluidPage(
|
||||
|
||||
server <- function(input, output) {
|
||||
output$contents <- renderTable({
|
||||
# input$file1 will be NULL initially. After the user selects
|
||||
# and uploads a file, it will be a data frame with 'name',
|
||||
# 'size', 'type', and 'datapath' columns. The 'datapath'
|
||||
# column will contain the local filenames where the data can
|
||||
# be found.
|
||||
inFile <- input$file1
|
||||
file <- input$file1
|
||||
ext <- tools::file_ext(file$datapath)
|
||||
|
||||
if (is.null(inFile))
|
||||
return(NULL)
|
||||
req(file)
|
||||
validate(need(ext == "csv", "Please upload a csv file"))
|
||||
|
||||
read.csv(inFile$datapath, header = input$header)
|
||||
read.csv(file$datapath, header = input$header)
|
||||
})
|
||||
}
|
||||
|
||||
shinyApp(ui, server)
|
||||
}
|
||||
|
||||
}
|
||||
\seealso{
|
||||
Other input elements: \code{\link{actionButton}},
|
||||
\code{\link{checkboxGroupInput}},
|
||||
\code{\link{checkboxInput}}, \code{\link{dateInput}},
|
||||
\code{\link{dateRangeInput}}, \code{\link{numericInput}},
|
||||
\code{\link{passwordInput}}, \code{\link{radioButtons}},
|
||||
\code{\link{selectInput}}, \code{\link{sliderInput}},
|
||||
\code{\link{submitButton}}, \code{\link{textAreaInput}},
|
||||
\code{\link{textInput}}, \code{\link{varSelectInput}}
|
||||
Other input elements:
|
||||
\code{\link{actionButton}()},
|
||||
\code{\link{checkboxGroupInput}()},
|
||||
\code{\link{checkboxInput}()},
|
||||
\code{\link{dateInput}()},
|
||||
\code{\link{dateRangeInput}()},
|
||||
\code{\link{numericInput}()},
|
||||
\code{\link{passwordInput}()},
|
||||
\code{\link{radioButtons}()},
|
||||
\code{\link{selectInput}()},
|
||||
\code{\link{sliderInput}()},
|
||||
\code{\link{submitButton}()},
|
||||
\code{\link{textAreaInput}()},
|
||||
\code{\link{textInput}()},
|
||||
\code{\link{varSelectInput}()}
|
||||
}
|
||||
\concept{input elements}
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
\alias{fillPage}
|
||||
\title{Create a page that fills the window}
|
||||
\usage{
|
||||
fillPage(..., padding = 0, title = NULL, bootstrap = TRUE,
|
||||
theme = NULL)
|
||||
fillPage(..., padding = 0, title = NULL, bootstrap = TRUE, theme = NULL)
|
||||
}
|
||||
\arguments{
|
||||
\item{...}{Elements to include within the page.}
|
||||
@@ -42,11 +41,11 @@ to the size of the window.
|
||||
|
||||
For example, \code{fluidPage(plotOutput("plot", height = "100\%"))} will not
|
||||
work as expected; the plot element's effective height will be \code{0},
|
||||
because the plot's containing elements (\code{<div>} and \code{<body>}) have
|
||||
because the plot's containing elements (\verb{<div>} and \verb{<body>}) have
|
||||
\emph{automatic} height; that is, they determine their own height based on
|
||||
the height of their contained elements. However,
|
||||
\code{fillPage(plotOutput("plot", height = "100\%"))} will work because
|
||||
\code{fillPage} fixes the \code{<body>} height at 100\% of the window height.
|
||||
\code{fillPage} fixes the \verb{<body>} height at 100\% of the window height.
|
||||
|
||||
Note that \code{fillPage(plotOutput("plot"))} will not cause the plot to fill
|
||||
the page. Like most Shiny output widgets, \code{plotOutput}'s default height
|
||||
@@ -82,3 +81,14 @@ fillPage(
|
||||
)
|
||||
)
|
||||
}
|
||||
\seealso{
|
||||
Other layout functions:
|
||||
\code{\link{fixedPage}()},
|
||||
\code{\link{flowLayout}()},
|
||||
\code{\link{fluidPage}()},
|
||||
\code{\link{navbarPage}()},
|
||||
\code{\link{sidebarLayout}()},
|
||||
\code{\link{splitLayout}()},
|
||||
\code{\link{verticalLayout}()}
|
||||
}
|
||||
\concept{layout functions}
|
||||
|
||||
@@ -66,4 +66,14 @@ shinyApp(ui, server = function(input, output) { })
|
||||
}
|
||||
\seealso{
|
||||
\code{\link[=column]{column()}}
|
||||
|
||||
Other layout functions:
|
||||
\code{\link{fillPage}()},
|
||||
\code{\link{flowLayout}()},
|
||||
\code{\link{fluidPage}()},
|
||||
\code{\link{navbarPage}()},
|
||||
\code{\link{sidebarLayout}()},
|
||||
\code{\link{splitLayout}()},
|
||||
\code{\link{verticalLayout}()}
|
||||
}
|
||||
\concept{layout functions}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user