Compare commits

...

341 Commits

Author SHA1 Message Date
Winston Chang
ba3d990d0b Merge remote-tracking branch 'origin/testServer-assign-env-once' into testserver-wip 2020-04-10 12:16:40 -05:00
Winston Chang
940ae4b39c Merge remote-tracking branch 'origin/testServer-small-updates' into testserver-wip 2020-04-10 12:16:27 -05:00
Alan Dipert
2d519aca15 WIP loadSuppor for apps passed to testServer 2020-04-10 06:01:33 +00:00
Alan Dipert
aac77ec74a Add appobj test 2020-04-10 05:41:45 +00:00
Alan Dipert
c32709eb53 add 12_counter test app to exercise runTests + testServer 2020-04-09 05:58:06 +00:00
Alan Dipert
e2ae14ca5a simplify buildMask() 2020-04-09 04:30:22 +00:00
Alan Dipert
4b87aa3252 simplify buildMask() 2020-04-09 04:29:30 +00:00
Alan Dipert
d0417c75d6 minor 2020-04-09 03:45:56 +00:00
Alan Dipert
00998b3e14 simplify buildMask() 2020-04-09 03:31:32 +00:00
Alan Dipert
616a56cbc7 document 2020-04-08 23:29:47 +00:00
Alan Dipert
02185b9827 Document/fix mock session $setEnv() and $setReturned() behavior 2020-04-08 23:29:06 +00:00
Alan Dipert
f013fcb5fd Revert minor in mock session 2020-04-08 22:54:27 +00:00
Alan Dipert
45f1e5fe50 mask creation: clean up, document, and align with rlang::new_data_mask() 2020-04-08 22:52:54 +00:00
Winston Chang
3994055056 App template updates 2020-04-08 17:14:15 -05:00
Winston Chang
374f7c2aa2 Rename tests/shinytests/ to tests/shinytest/ 2020-04-08 17:14:15 -05:00
Winston Chang
27ad5d6110 Template update 2020-04-08 17:14:15 -05:00
Winston Chang
d374f1dc88 Refinements to app template 2020-04-08 17:14:15 -05:00
trestletech
38349f354d Added skeleton function and example 2020-04-08 17:14:15 -05:00
Alan Dipert
d7feddb131 Improve makeMask comment 2020-04-08 16:50:20 +00:00
Winston Chang
1433439215 Merge pull request #2737 from rstudio/inline-markdown
Add shiny::markdown() for inline Markdown
2020-04-08 11:28:27 -05:00
Alan Dipert
4c8dc09f67 NEWS.md 2020-04-08 16:15:22 +00:00
Alan Dipert
80b43942b0 Bump glue dep 2020-04-08 16:14:01 +00:00
Winston Chang
b709b53b6a Merge pull request #2807 from rstudio/serverModule-testModule
moduleServer/testServer overhaul
2020-04-08 10:58:03 -05:00
Alan Dipert
f4e3e5b618 server => module 2020-04-08 05:06:30 +00:00
Alan Dipert
bac7299359 Remove strings from expect_error 2020-04-08 04:57:14 +00:00
Alan Dipert
fc6f535edd Clarify testServer lexenv assertions 2020-04-08 04:54:32 +00:00
Alan Dipert
7e2ffab62c Use base versions of a couple rlang::env_* functions 2020-04-08 04:44:25 +00:00
Alan Dipert
214d721380 Move session$env sanity check out of makeMask and into testServer 2020-04-08 04:41:51 +00:00
Alan Dipert
2f8227e652 Un-inline assignment 2020-04-08 04:36:00 +00:00
Alan Dipert
c0c02d290f Remove unused variable 2020-04-08 04:35:40 +00:00
Alan Dipert
bc2aa71888 Use vapply in mapNames() 2020-04-08 04:27:40 +00:00
Alan Dipert
7f187d1553 Add markdown() NEWS item 2020-04-08 03:04:46 +00:00
Alan Dipert
81b1f4fdc1 Inline markdown tests, add to docs 2020-04-07 22:48:04 +00:00
Alan Dipert
15f088f10a Merge remote-tracking branch 'origin/master' into inline-markdown 2020-04-07 20:47:11 +00:00
Alan Dipert
286f12522b document 2020-04-07 18:40:40 +00:00
Alan Dipert
9d8a6d0142 Document new R6 methods 2020-04-07 18:40:34 +00:00
Alan Dipert
a2dd97cc74 Merge remote-tracking branch 'origin/master' into serverModule-testModule 2020-04-06 23:13:33 +00:00
Alan Dipert
1d9a6ea3c0 getEnv() => env, docs 2020-04-06 23:11:51 +00:00
Alan Dipert
3ca8b1017b Tests pass \o/ 2020-04-06 22:36:09 +00:00
Winston Chang
ecd7c76aee Merge pull request #2764 from rstudio/runTests-aggregate
Tweak runTests() output format
2020-04-06 15:59:06 -05:00
Alan Dipert
70edcd62b9 Getting there 2020-04-03 23:04:50 +00:00
Alan Dipert
90f531888c fix one failing test 2020-04-03 22:06:14 +00:00
Alan Dipert
953de733e7 nested module tests pass now, many others fail %-) 2020-04-02 23:26:02 +00:00
Alan Dipert
e0ed443319 WIP mock session scoped proxy 2020-04-02 21:33:57 +00:00
Alan Dipert
1487720fd8 WIP more markdown() tests 2020-04-01 21:38:39 +00:00
Alan Dipert
828567e0ce Add failing proxy-related and ns() related tests 2020-04-01 21:31:39 +00:00
Alan Dipert
78da4c7fce Merge remote-tracking branch 'origin/master' into serverModule-testModule 2020-04-01 07:26:43 +00:00
Alan Dipert
7f80bfd2cb document 2020-04-01 07:01:57 +00:00
Alan Dipert
7e3deb5e3f document 2020-04-01 06:55:44 +00:00
Alan Dipert
5475ec4f0c document 2020-04-01 06:48:34 +00:00
Alan Dipert
58b4585b57 Doc and test updates 2020-04-01 06:45:18 +00:00
Alan Dipert
cf9ab1c47b appobj coercion works 2020-03-31 21:36:20 +00:00
Alan Dipert
65233cdd5c First passing app dir test for testServer overhaul 2020-03-31 06:33:01 +00:00
Alan Dipert
9d13cb644d test-module.R => test-server.R 2020-03-31 05:36:03 +00:00
Alan Dipert
dd9e0343e8 More test progress 2020-03-31 05:29:42 +00:00
Alan Dipert
bb4aaa2a78 Bring back scope tests 2020-03-31 05:02:31 +00:00
Alan Dipert
0023418b94 More test reorg 2020-03-30 22:55:27 +00:00
Alan Dipert
ec2c9ecea0 Split up and rename various tests 2020-03-27 22:43:29 +00:00
Barret Schloerke
59759398a6 Update actionButton example (#2806)
* Update actionButton example

* Fix link name in example
2020-03-27 17:00:56 -04:00
Alan Dipert
c4852cb451 Desired environment semantics are working 2020-03-25 22:40:08 +00:00
Winston Chang
99880d6e8a Merge pull request #2796 from rstudio/actionButton_class
Add css class examples for actionButton and actionLink
2020-03-24 09:52:23 -05:00
Alan Dipert
b005799d92 Add back many working/converted tests 2020-03-23 23:01:53 +00:00
Barret Schloerke
72f86dac27 Update Node.js build scripts (#2800)
* automatic formatting

* Update to the latest & greatest

* `./tools` `yarn build`

* Remove `newer` from grunt as it causes more problems than it solves. yarn build
2020-03-20 15:59:10 -04:00
Barret Schloerke
83628facb3 Use roxygen2 reexport setup for htmltools and fastmap (#2795)
* Remove all hard copied man files

* Move fastmap reexports into ./R/rexport-fastmap.R

* Update htmltools man script to look for the latest tag and make a reexports file

* document

* Update htmltools reexports to listen to ./inst/_htmltools_reexports.json file. Fix pkgdown failure.

* Allow for any package reexports. Currently fastmap and htmltools

* remove progress dependency

* add back skip on cran for pkgdown

* Test pkgdown only if called using devtools::test or within CI

* Removed outdated import docs file. Moved pkgdown and reexports files into ./tools/documentation. Updated travis file.

* add local test for pkgdown

* updated comments and added a debug comment

* print the repo url and close it

* print the downloaded repo tag info

* use gh package and make sure it's installed

* add PAT to travis and remove username from gh::gh call

* skip pkgdown test on cran and add comments
2020-03-20 14:25:18 -04:00
Alan Dipert
f6e171823a Merge remote-tracking branch 'origin/master' into serverModule-testModule 2020-03-19 20:48:07 +00:00
Barret Schloerke
9b743a319f Add ./revdep folder output and script (#2790)
* Revdep check. 719 - CRAN, 117 - BioConductor; 0 new problems; 3 failed to check

* fix last few install failures.  836 pass. 0 untested. 0 failures.

* add revdep script
2020-03-19 11:43:37 -05:00
Barret Schloerke
eedf2a6cc8 add examples for actionButton and actionLink which adds extra css classes 2020-03-17 14:21:20 -04:00
Winston Chang
e1e738f772 Change indenting of module examples 2020-03-17 13:01:50 -05:00
Winston Chang
182ff3df88 Merge tag 'v1.4.0.2'
Shiny 1.4.0.2 on CRAN
2020-03-16 12:34:10 -05:00
Barret Schloerke
23fde95f9e Add class 'function' to reactive and reactiveVal objects (#2793)
* add the class 'function' to a reactive object

* add the class 'function' to a reactiveVal object

* add test to make sure the reactive and reactiveVal objects are functions

* Add news item
2020-03-16 10:42:28 -04:00
Barret Schloerke
78f9132eb3 Fix Travis checks (#2791)
* make sure the server is only run if the example is interactive

* get travis to pass for now

* Update modules.R

* Add S3 class to MockShinySession

* un-skip test

* Update roxygen level

Co-authored-by: Alan Dipert <alan@dipert.org>
2020-03-12 17:42:38 -04:00
Winston Chang
84b7211588 Bump version to 1.4.0.2 2020-03-12 15:42:26 -05:00
Winston Chang
2793e15c26 Add link 2020-03-12 15:41:21 -05:00
Winston Chang
36bd76607a Skip debounce/throttle tests on CRAN 2020-03-12 15:41:16 -05:00
Barret Schloerke
e17f416bb0 Update roxygen level 2020-03-12 16:30:18 -04:00
Barret Schloerke
a577b1e22e un-skip test 2020-03-12 16:20:13 -04:00
Alan Dipert
2d324c77c1 Add S3 class to MockShinySession 2020-03-12 13:18:23 -07:00
Alan Dipert
88374eca74 Update modules.R 2020-03-12 13:16:55 -07:00
Barret Schloerke
386135788b get travis to pass for now 2020-03-12 16:12:05 -04:00
Barret Schloerke
a943d955dd make sure the server is only run if the example is interactive 2020-03-12 15:58:46 -04:00
Winston Chang
15476ac32e Merge pull request #2789 from rstudio/skip-tests-timing
Skip debounce/throttle tests on CRAN
2020-03-12 11:16:20 -05:00
Winston Chang
17fb5b9eae Add link 2020-03-12 10:00:36 -05:00
Winston Chang
fd27a0dfa2 Skip debounce/throttle tests on CRAN 2020-03-12 09:46:18 -05:00
Winston Chang
5ffe69ec6c Merge tag 'v1.4.0.1' 2020-03-12 09:21:07 -05:00
Carson
f5723b2a4d revert man/ changes to reflect CRAN version of htmltools 2020-03-11 12:04:58 -05:00
Alan Dipert
9e959a88f1 tests 2020-03-05 18:02:26 +00:00
Alan Dipert
09abac41c5 minor reformat 2020-03-05 17:03:15 +00:00
Alan Dipert
1dbf013c1b markdown(): Improve docs; add .noWS; class result as html 2020-03-05 16:57:43 +00:00
Alan Dipert
a637d5b126 Merge remote-tracking branch 'origin/master' into inline-markdown 2020-03-04 21:25:57 +00:00
Alan Dipert
d409183751 Merge remote-tracking branch 'origin/master' into runTests-aggregate 2020-03-04 21:03:50 +00:00
Alan Dipert
e8feef1ce0 Address feedback 2020-03-04 21:03:04 +00:00
Winston Chang
01491cc696 Merge pull request #2772 from rstudio/test-nest-testModule-testServer
Small changes to testModule()/testServer() semantics
2020-03-04 14:58:30 -06:00
Alan Dipert
568a3f28cf Change test to not be locale-dependent 2020-03-04 20:48:21 +00:00
Winston Chang
02219df480 Merge pull request #2773 from rstudio/wch-module
Add moduleServer function
2020-03-04 09:24:58 -06:00
Winston Chang
e006ca51ee Add NEWS item 2020-03-04 09:23:27 -06:00
Winston Chang
86f651f3ec Add moduleServer function 2020-03-04 09:23:27 -06:00
Carson
212b33a0ce bump version 2020-03-03 18:50:41 -06:00
Carson
6b7a121161 yarn build 2020-03-03 18:50:34 -06:00
Carson Sievert
c89da718b1 Merge pull request #2777 from rstudio/fix-docs
Run tools/updateHtmltools.R
2020-03-03 18:40:27 -06:00
Carson
eef3ae8387 update news and update htmltools docs 2020-03-03 16:45:57 -06:00
Alan Dipert
0975a61725 Add test to mitigate shadow with unquote 2020-03-03 22:32:59 +00:00
Winston Chang
0c53d54347 Merge pull request #2776 from rstudio/grid-r-devel
Patches for grid 4.0
2020-03-03 16:12:39 -06:00
Carson
cbbb04cf69 yarn build 2020-03-03 15:52:25 -06:00
Carson
120baf0a6e review feedback 2020-03-03 15:34:32 -06:00
Carson
685dc7cc3a Updates for new grid in r-devel 2020-03-03 15:30:12 -06:00
Alan Dipert
2fbb2ac77b Merge remote-tracking branch 'origin/master' into test-nest-testModule-testServer 2020-03-03 19:25:49 +00:00
Alan Dipert
2832db7aba New session$env test 2020-03-03 19:25:14 +00:00
Alan Dipert
18f2471d7c Fix some roxygen errors 2020-03-03 19:08:49 +00:00
Alan Dipert
ea28f5a61b Minor changes and tests 2020-03-03 18:58:42 +00:00
Winston Chang
fe9cc6038e Merge pull request #2774 from rstudio/no-slack-notifications
Remove slack notifications
2020-03-03 12:09:39 -06:00
Barret Schloerke
5ed335c499 Remove slack notifications 2020-03-03 12:42:48 -05:00
Alan Dipert
fd04b97496 Fix global reference test inside testServer 2020-03-02 17:56:47 +00:00
Alan Dipert
4c9d281b59 Subtle change to .testModule() semantics 2020-02-28 22:49:37 +00:00
Alan Dipert
cfb683419f Remove Rd 2020-02-25 20:30:34 +00:00
Alan Dipert
97887bdf02 Add noRd to private function 2020-02-25 20:30:07 +00:00
Alan Dipert
38ea693e73 NEWS.md updates 2020-02-25 18:13:49 +00:00
Alan Dipert
582a0ea6a5 Remove redundant new test 2020-02-25 17:21:19 +00:00
Alan Dipert
71b9f0907e Merge remote-tracking branch 'origin/master' into runTests-aggregate 2020-02-25 16:39:54 +00:00
Alan Dipert
82b82b714d Fix some roxygen errors 2020-02-25 16:27:01 +00:00
Alan Dipert
6356228053 Normalize runTests() output, improve documentation of returned dataframe 2020-02-25 00:08:51 +00:00
Alan Dipert
18fd677550 Pass existing runTests() tests 2020-02-24 22:48:08 +00:00
Alan Dipert
d9698df721 More progress on runTests() format 2020-02-24 22:14:24 +00:00
Joe Cheng
2ee06a7cbf Revert "Support shiny.autoreload even when there are errors"
This reverts commit cf2ba90b1d.
2020-02-22 12:21:58 -08:00
Joe Cheng
cf2ba90b1d Support shiny.autoreload even when there are errors 2020-02-22 12:20:12 -08:00
Alan Dipert
8124b2143b revert names in app1 tests 2020-02-21 23:57:52 +00:00
Alan Dipert
5361573051 Add working runTests test 2020-02-21 23:35:19 +00:00
Alan Dipert
1d377c868d runTests() output 2020-02-21 22:17:34 +00:00
Alan Dipert
b0a855a326 Make improvements suggested by @schloerke 2020-02-19 20:39:28 +00:00
Alan Dipert
fa35f29596 add_result() for test run 2020-02-19 06:55:32 +00:00
Alan Dipert
f429d23b6e add_result() for test run 2020-02-19 06:54:46 +00:00
Alan Dipert
eeeb903b70 add_result() for test run 2020-02-19 06:54:11 +00:00
Alan Dipert
78f12c4a75 Type stability changes to shinytestrun object 2020-02-19 06:50:58 +00:00
Barret Schloerke
c69f34d1e2 update js files (version bump) 2020-02-18 13:47:02 -05:00
Barret Schloerke
ccfcc5d8b4 add news item 2020-02-18 13:47:02 -05:00
Barret Schloerke
210c248264 bump version 2020-02-18 13:47:02 -05:00
Barret Schloerke
e3258657d0 Invoke onSessionEnded callbacks with self reactive domain 2020-02-18 13:47:02 -05:00
Barret Schloerke
dbc518bf53 Fix broken timer tests and check htmltools docs (#2758)
* Adjust time so that it's in seconds and use expect_true to use regular R dispatch

* Execute './tools/updateHtmltoolsMan.R'

* add check for htmltools docs being up to date
2020-02-14 11:36:51 -05:00
Winston Chang
cdbdb4510e Fix NEWS item 2020-01-16 11:43:51 -06:00
Joe Cheng
e7ec5e5ba4 Merge pull request #2689 from rstudio/joe/feature/bs4-compat
bs4 compatibility
2020-01-13 11:59:15 -08:00
Carson
03d8a7f296 document with modern roxygen 2020-01-13 13:28:54 -06:00
Carson
480035c065 undo unnecessary diff; yarn build 2020-01-13 13:04:44 -06:00
Winston Chang
b32c18cf72 Merge pull request #2722 from rstudio/appveyor-cache
Bust appveyor cache every time the DESCRIPTION file updates
2020-01-08 14:27:58 -06:00
Barret Schloerke
337a6b276a Add more comments about why we are busting the appveyor cache 2020-01-08 14:57:06 -05:00
Barret Schloerke
06cf1f9477 Add comment about why we are busting the cache 2020-01-08 14:55:12 -05:00
Winston Chang
190cfd2b7a Merge pull request #2721 from rstudio/yarn-frozen-lockfile
Use a frozen lock file within CI
2020-01-08 13:21:47 -06:00
Joe Cheng
63035b4d66 No need for bg-danger, progress-bar-danger is now in bs3compat 2020-01-07 13:55:46 -08:00
Joe Cheng
6a11c8fcb1 Remove .col-form-label
I must've copied this from a bs4 example without understanding
what it's for; it's intended for horizontal form labels, which
we don't do
2020-01-07 13:55:23 -08:00
Joe Cheng
33ffb006e3 Get rid of striped progress bar style
The bs4 striped progress bar directives have changed,
but also the stripes look pretty dated at this point
2020-01-07 13:55:23 -08:00
Joe Cheng
162e7f63a9 Remove branch from htmltools remote 2020-01-07 13:54:55 -08:00
Joe Cheng
bb581eeec4 Remove btn-outline-secondary
We're handling btn-default in bs3compat
2020-01-07 13:54:55 -08:00
Joe Cheng
272c555bc5 Remove unnecessary bs4 compat shims from showcase 2020-01-07 13:54:55 -08:00
Joe Cheng
fb64caab23 Remove unnecessary bs4 classes
Since these classes were added, we've decided to handle more of this
kind of thing in the bootscss package, so bs3 markup can work without
modification in many cases.
2020-01-07 13:54:55 -08:00
Carson
6f2a74a46d requires htmltools >= 0.4.0.9001 2020-01-07 13:54:41 -08:00
Carson
ec65a74492 Need to de-active any nav tab, not just navs in a dropdown 2020-01-07 13:53:57 -08:00
Carson
ba791c42fa showcase compatibility 2020-01-07 13:53:39 -08:00
Carson
5896667c36 For some reason event.relatedTarget isn't populated when the previously active item is a dropdown item 2020-01-07 13:53:39 -08:00
Carson
003c949d38 Compatibility for checkboxes will happen via bs4 shims 2020-01-07 13:53:21 -08:00
Carson
d31394254c progress-bar-striped needs to appear on the actual progress bar (not it's container) 2020-01-07 13:53:21 -08:00
Carson
1a497e246c progress-bar-danger class has been replaced by bg-danger 2020-01-07 13:53:06 -08:00
Carson
d24276aa54 btn-outline-secondary is visually closer to btn-default (compared to btn-secondary) 2020-01-07 13:52:49 -08:00
Carson
6ed21a3e6b dateRangeInput() should use input-group-sm, not input-sm or form-control-sm
The former is supported in both bs3 and bs4 and ensures consistent small sizing of the input groups
2020-01-07 13:52:49 -08:00
Carson
8066f9ce96 remove debugger; more detailed comment 2020-01-07 13:52:49 -08:00
Carson
a0276ec1ce wip bs4 compat work 2020-01-07 13:52:33 -08:00
Joe Cheng
2ab925a24c wip2 2020-01-07 13:52:33 -08:00
Joe Cheng
78fbad7d8d wip1 2020-01-07 13:52:13 -08:00
Alan Dipert
6652ae3042 markdown(): improve docs, simplify call to markdown_html(), default to extensions = TRUE 2020-01-06 22:43:04 +00:00
Alan Dipert
aa12ab7d76 Add shiny::markdown() for inline Markdown 2020-01-04 00:02:30 +00:00
Winston Chang
89be4bdce9 Merge pull request #2728 from rstudio/wch-fix-timer
Timer functions always use ms
2019-12-19 13:12:35 -06:00
Winston Chang
d09a064471 Use test_path 2019-12-13 15:45:17 -06:00
Alan Dipert
2b18ca5a6c .testModule(): remove args parameter fixes #2709 (#2713)
* .testModule(): Don't ignore args parameter, fixes #2709

* .testModule(): eliminate args, rely on dynamic dots

* Expand testModule() dots support, add dynamic dots test

* More ... tests

* testModule(): document dynamic dots

* Tighten up ... docs

* document

* testModule(): sundry improvements to docs and tests
2019-12-13 15:38:45 -06:00
Winston Chang
6bc2f18bbf Timer functions always use ms, and better names. Closes #2725 2019-12-13 15:30:47 -06:00
Alan Dipert
fbb892d84e Add MockShinySession$makeScope() (#2714)
* Add MockShinySession$makeScope(), fixes #2712

* Port some relevant ShinySession$defineOutput() behavior to MockShinySession$defineOutput()

* Add nested module test

* Add test for defineOutput() type check

* minor test improvement

* testModule(): improve inner module test, pass reactive to inner
2019-12-12 16:49:18 -06:00
Barret Schloerke
4efb7c20e4 add install cmd 2019-12-10 12:36:23 -05:00
Barret Schloerke
4beb1f07a6 Bust appveyor cache every time the DESCRIPTION file updates 2019-12-09 15:27:17 -05:00
Barret Schloerke
45e640e5f9 Use a frozen lock file within CI
https://yarnpkg.com/lang/en/docs/cli/install/#toc-yarn-install-frozen-lockfile
> Don’t generate a yarn.lock lockfile and fail if an update is needed.
2019-12-09 15:07:12 -05:00
Barret Schloerke
e84beffee3 Merge pull request #2717 from akgold/label-file-observer
Add label to file reload observer
2019-12-06 14:42:08 -05:00
Winston Chang
e07c7483a7 Merge pull request #2719 from rstudio/wch-fix-odd-chars
Use as.raw instead of charToRaw
2019-12-04 12:31:57 -06:00
Winston Chang
34ec7bf5eb Use as.raw instead of charToRaw
When the package is built, the string with odd characters is marked with the
encoding of the build system. When the build system uses the C locale and the
running system uses a UTF-8 locale (like en_US.UTF-8), this results in a warning
when this function is first accessed. Using as.raw() lets us avoid using a
string altogether.
2019-12-04 10:47:21 -06:00
Barret Schloerke
01b20a4829 display auto reload base directory for reactlog label 2019-12-03 15:16:18 -05:00
Winston Chang
45ea898da4 Rebuild docs with roxygen2 7.0.2 2019-12-03 12:28:06 -06:00
Alex Gold
fd34c5070f Add label to file reload observer 2019-12-02 10:03:11 -05:00
Winston Chang
6c409d96c1 Bump node version on Travis 2019-11-22 14:09:58 -06:00
Winston Chang
0cbe4bb3d4 Rebuild docs with roxygen2 7.0.1 2019-11-22 13:07:44 -06:00
Winston Chang
d04a990235 Merge pull request #2707 from rstudio/wch-outputinfo-null
getCurrentOutputInfo(): return NULL if not in an output
2019-11-22 12:38:05 -06:00
Winston Chang
4747c87632 Rebuild shiny.js 2019-11-21 16:31:51 -06:00
Winston Chang
f57452c7bf Update docs 2019-11-21 16:30:38 -06:00
Winston Chang
9a8e2eb675 getCurrentOutputInfo(): return NULL if not in an output 2019-11-21 16:16:52 -06:00
Winston Chang
8ef7f3cbe2 Merge pull request #2701 from rstudio/wch-update-roxygen
Update roxygen2 to 7.0.0
2019-11-13 15:01:29 -06:00
Winston Chang
de30a65f01 Update documentation of Progress and MockShinySesssion 2019-11-13 15:01:01 -06:00
Winston Chang
0bcf613195 Update to roxygen2 7.0.0 2019-11-13 12:10:57 -06:00
Winston Chang
89fd9004d0 Merge pull request #2585 from rstudio/jeff/feature/test
Add a test runner
2019-11-13 11:53:00 -06:00
trestletech
b2be108db1 Add a message to clarify what app is being tested, support setting progress on mock session. 2019-11-13 11:43:50 -06:00
trestletech
6102c44b70 Attempt to pin roxygen2 2019-11-07 13:26:15 -06:00
trestletech
327cdc8e41 Don't use GH deps for appveyor
see 89feba870d.
2019-11-07 12:51:03 -06:00
trestletech
0bc3613989 PR feedback 2019-11-06 15:58:30 -06:00
Jeff Allen
30cea871f9 Expand testServer/Module docs (#2694)
* Merge and expand testmodule/server docs

* Alos->also
2019-11-06 20:29:44 +00:00
trestletech
5f332fe4db Set working dir in testServer so the app runs in the proper dir. 2019-11-01 16:52:43 -05:00
trestletech
7ee7f2716b Load shiny and inherit from global env. Non-error are no NA and errors are passed through. 2019-11-01 16:40:45 -05:00
trestletech
5e8c39cb1e Add entry in pkgdown 2019-11-01 11:26:23 -05:00
trestletech
ee355200b3 Rename testApp -> runTests 2019-11-01 11:25:47 -05:00
trestletech
986fbe2254 Merge remote-tracking branch 'origin/master' into jeff/feature/test 2019-11-01 11:23:24 -05:00
Jeff Allen
32f93a2be1 Integration Testing Docs (#2691)
* Update roxygen and regenerate.

Mostly just whitespace changes and  `code` -> `verb`.

* R6 documentation for MockShinySession

* Install roxygen from GH

* % are now auto-escaped

(We still need to go find the rest)

* Fixed the ramining \% in roxygen

Found looking for ^#'.*\\% in all R files, so I believe this is all of them.

* Regenerate docs

* Decreate indent in roxygen so paragraphs don't get interpreted as code blocks.

https://github.com/r-lib/roxygen2/issues/948#issuecomment-546386172

* Namespace

* Add MockShinySession reference to pkgdown.

* Clean up test warnings

* Export session
2019-11-01 02:33:58 +00:00
Winston Chang
ab79065c13 Merge pull request #2690 from rstudio/wch-date-color
Datepicker: make disabled months and years lighter gray
2019-10-31 12:16:18 -05:00
Winston Chang
77171b7894 Make cursor indicate when dates are not selectable 2019-10-31 12:09:18 -05:00
Winston Chang
cce8ddb84f Update NEWS 2019-10-30 16:05:55 -05:00
Winston Chang
648b7e5911 Datepicker: make disabled months and years lighter gray 2019-10-30 16:01:29 -05:00
Jeff Allen
67a66fdc93 Merge pull request #2682 from rstudio/jeff/int-test
Introduce integration testing framework
2019-10-30 18:36:44 +00:00
trestletech
5fbaa26d05 Remove vignette. 2019-10-30 11:29:58 -04:00
trestletech
1f4a3c4fd2 Regenerate docs 2019-10-28 23:14:25 -04:00
trestletech
959dc7ffd4 PR feedback 2019-10-28 22:57:30 -04:00
trestletech
0e34221cac How do I still get paid to do this? 2019-10-25 16:54:10 -05:00
trestletech
0cad13b3a3 Placeholder docs for MockShinySession
(More to come in subsequent PR)
2019-10-25 16:47:10 -05:00
trestletech
0776f71ca3 Export session 2019-10-25 16:27:45 -05:00
trestletech
5a74e369ce Implement missing test. 2019-10-25 16:23:16 -05:00
trestletech
799c5ac662 Clean up test warnings 2019-10-25 16:20:33 -05:00
Jeff Allen
1080cf0ef4 Merge pull request #2686 from rstudio/jeff/autoload
Message when autoloading R/ files
2019-10-25 20:16:42 +00:00
trestletech
867d49e3fb Pin to the beginning of the file path. 2019-10-25 15:02:39 -05:00
trestletech
c7be406099 Change URL 2019-10-25 14:21:32 -05:00
trestletech
37257e77ce Disable autoloading with a R/_disable_autoload.R file. 2019-10-25 14:14:46 -05:00
trestletech
270d9ff0fc Add message about loading R/ 2019-10-25 14:02:50 -05:00
trestletech
34b48598d9 Merge remote-tracking branch 'origin/master' into jeff/int-test 2019-10-25 11:23:15 -05:00
trestletech
5105ecb148 Cleaning up the vignette 2019-10-24 14:46:54 -05:00
trestletech
f47b151458 Test improvements for Windows and make CHECK pass. 2019-10-24 11:50:07 -05:00
Jeff Allen
d3f15a58fc Merge pull request #2675 from rstudio/jeff/mock-session
Introduce a MockShinySession object
2019-10-24 15:21:30 +00:00
trestletech
42f6adb7fa Handle Joe's feedback. 2019-10-24 10:20:54 -05:00
trestletech
263f8a8e7d Introduce integration testing functionality 2019-10-24 10:07:23 -05:00
trestletech
3a42d30cfd Simplify run_now() 2019-10-24 09:53:37 -05:00
trestletech
9275217a5a Refine which methods merit warnings 2019-10-22 15:43:26 -05:00
trestletech
1fed19ad68 Export flushReact method 2019-10-22 09:59:20 -05:00
trestletech
6a8a78abd1 Bring in promise helpers and test for getOutput auto-flushing 2019-10-22 09:47:09 -05:00
trestletech
de69f51084 Rename parameter, destroy old outputs 2019-10-22 09:43:37 -05:00
Winston Chang
c81a3f39fd Update NEWS 2019-10-21 16:57:01 -05:00
Winston Chang
6fcb925e34 Merge pull request #2652 from ahmohamed/master
Fix debounce() behavior when r() throws an error
2019-10-21 16:54:59 -05:00
Winston Chang
8823b7280a Merge branch 'master' into hadley-text-doc 2019-10-21 16:45:53 -05:00
Winston Chang
ebadad97a8 Merge pull request #2612 from hadley/file-type
Improve inputFile() accept documentation
2019-10-21 16:43:01 -05:00
Winston Chang
a095c39626 Merge pull request #2616 from hadley/bookmarking-docs
Tweak shinyApp docs about bookmarking
2019-10-21 16:42:07 -05:00
Winston Chang
fb9bcb44c3 Merge branch 'insert-remove-ui' of https://github.com/hadley/shiny into hadley-insert-remove-ui 2019-10-21 16:40:06 -05:00
trestletech
38f593450a PR feedback 2019-10-21 15:35:05 -05:00
trestletech
6d44f2c5cb Align default parameter values with real session 2019-10-21 15:32:37 -05:00
trestletech
d1786a64c4 Try to fix failing Windows test
Perhaps Sys.time isn't high enough resolution there?
2019-10-18 15:33:07 -05:00
trestletech
616ae99c0b Include equality in scheduling comparisons
In real life, the odds that a Sys.time() call is going to hit this equality branch is pretty small as the clock is so precise. However, for testing it's nice to be able to say "this should fire in 10ms, now elapse 10ms" and then confirm that it fired. Without this, you have to pad your delays in order to see the event trigger.
2019-10-18 15:22:03 -05:00
trestletech
4d2ff80788 Introduce MockShinySession 2019-10-18 15:20:44 -05:00
Jeff Allen
005295fd4c Merge pull request #2665 from rstudio/jeff/session-timers
Best-effort task scheduling through the session
2019-10-18 20:12:22 +00:00
trestletech
d6b46f8243 Bring back the good parts of a003 2019-10-18 13:58:42 -05:00
trestletech
bac35e8f1b Revert "PR feedback. Broke tests because of dependency on session, though, so might revert."
This reverts commit a003c4da85.
2019-10-18 13:50:30 -05:00
trestletech
a003c4da85 PR feedback. Broke tests because of dependency on session, though, so might revert. 2019-10-17 14:01:58 -05:00
trestletech
0ae8e4fe8a Consolidate to two Timer classes and simplify conditionals 2019-10-16 14:49:01 -05:00
trestletech
d3667dfc77 Attempt to get the current time from the session, if available. 2019-10-15 15:32:59 -05:00
trestletech
54c5467dc6 Unrelated: fix autoload tests. 2019-10-15 15:02:16 -05:00
trestletech
d01f0300a5 Add mock timer class 2019-10-15 14:59:36 -05:00
trestletech
bff207008f Best-effort task scheduling through the session
Currently a no-op change, as the session just passes through to the global scheduleTask implementation. But this allows us to mock the method for testing.
2019-10-15 14:24:10 -05:00
trestletech
ed739f95ff Revert "Best-effort task scheduling through the session"
This reverts commit bb4de1336c.
2019-10-15 14:22:31 -05:00
trestletech
bb4de1336c Best-effort task scheduling through the session
Currently a no-op change, as the session just passes through to the global scheduleTask implementation. But this allows us to mock the method for testing.
2019-10-15 14:21:44 -05:00
Winston Chang
f7205558d2 Make shiny.autoload.r default to TRUE (#2659)
* Make shiny.autoload.r default to TRUE

* Update comments
2019-10-15 12:24:39 -05:00
Winston Chang
1318544ecf Update NEWS 2019-10-11 14:58:17 -05:00
Winston Chang
a81c161434 Merge pull request #2658 from rstudio/fix-data-table
Preserve matrix dimensions in dataTablesJSON
2019-10-11 14:56:21 -05:00
Winston Chang
73acdc755f Merge pull request #2650 from rstudio/wch-travis-r-versions
Run Travis checks on more R versions
2019-10-10 10:18:21 -05:00
Winston Chang
dd84ea8fda Merge branch 'master' into wch-travis-r-versions 2019-10-10 10:17:33 -05:00
Winston Chang
a2a4e40821 Bump version to 1.4.0.9000 2019-10-10 10:06:12 -05:00
Winston Chang
509f54d68c Merge tag 'v1.4.0'
shiny 1.4.0 on CRAN
2019-10-10 10:04:03 -05:00
Winston Chang
27ce460ea4 Preserve matrix dimensions in dataTablesJSON. Fixes #2653 2019-10-08 16:04:03 -05:00
Alan Dipert
116794ad77 Use pkgdown for reference page generation (#2651)
* Add _pkgdown.yml, remove inst/staticdocs/index.r

* Update pkgdown.yml

* Fix pkgdown (nee staticdocs) test so that it fails as it should

* Fix pkgdown test by adding shinyServer and shinyUI to list of intentionally unindexed functions

* Remove old staticdocs test

* Fix "Boilerplate" section of reference docs

* Fix CMD CHECK

* Fix typo

* Use file-based test in get_exported()

* Skip pkgdown check on CRAN

* Fix typo in pkgdown test
2019-10-07 15:18:26 -05:00
Winston Chang
89feba870d Don't use dependency release candidates in Travis 2019-10-07 14:51:36 -05:00
Winston Chang
2a980601c0 Use absolute URL for CONTRIBUTING.md 2019-10-07 12:26:37 -05:00
Winston Chang
e1fd8ae910 Fix CONTRIBUTING.md link 2019-10-07 12:24:54 -05:00
Joe Cheng
9cb415008c Update link 2019-10-04 16:16:32 -07:00
Ahmed Mohamed
26ba9bf94a Fix debounce() behavior when r() throws an error 2019-10-04 11:58:22 +10:00
Winston Chang
fb091ca195 Restructure NEWS 2019-10-02 15:26:14 -05:00
Winston Chang
99a7dca3ce Relax test so it passes on R 3.3 and below 2019-09-30 16:28:38 -05:00
Winston Chang
a1a03d94be Run Travis on more R versions 2019-09-30 16:05:31 -05:00
trestletech
85a2d41a72 Merge remote-tracking branch 'origin/master' into jeff/feature/test 2019-09-30 09:55:11 -05:00
Jeff Allen
89bd7e9011 Merge pull request #2647 from rstudio/jeff/cla
Update contributing instructions for cla-assistant.
2019-09-30 14:48:38 +00:00
trestletech
ececdf42a7 Update contributing instructions for cla-assistant. 2019-09-30 09:46:57 -05:00
Jeff Allen
2cf03de8b8 Don't notify slack on success 2019-09-27 18:07:08 +00:00
Winston Chang
c8daa1730b Merge pull request #2643 from rstudio/wch-fix-stack-tests
Disable stack tests on CRAN
2019-09-26 16:59:58 -05:00
Winston Chang
d195b595dd Disable call stack tests on CRAN 2019-09-26 16:23:52 -05:00
Barret Schloerke
ff3f7adff2 Merge pull request #2637 from rstudio/rc-barret-utils-packageVersion
Namespace packageVersion
2019-09-24 18:13:24 -04:00
Barret Schloerke
37781a9df7 namespace packageVersion 2019-09-24 17:36:45 -04:00
Joe Cheng
ca1c60e00e Merge pull request #2632 from rstudio/carson/jquery-legacy
Opt-in to jQuery 1.12.1
2019-09-20 17:52:37 -07:00
Carson
649f382291 Library updates -> Potentially breaking changes 2019-09-20 15:43:38 -05:00
Carson
103a35c81b review feedback 2019-09-20 15:43:38 -05:00
Carson
5af341bfdb document 2019-09-20 15:43:38 -05:00
Carson
7c7110cd83 Do nothing if the package isn't installed or meets the version requirement 2019-09-20 15:43:38 -05:00
Carson
c4ea489bff news feedback 2019-09-20 15:43:38 -05:00
Carson
60b3b6ff03 jquery legacy is 1.12.4, not 1.12.1 2019-09-20 15:43:38 -05:00
Carson
1510dca065 update news 2019-09-20 15:43:38 -05:00
Carson
2c49375928 Provide an option, shiny.jquery.version, to opt-in into jQuery 1.12.1 2019-09-20 15:43:38 -05:00
Carson
f9fc22c48b Emit an upgrade message if an old version htmlwidgets is installed 2019-09-20 15:43:38 -05:00
Alan Dipert
8d14e7ab04 Merge pull request #2625 from rstudio/fix-selectize-update
Fix updateSelectizeInput(), fixes #2624
2019-09-20 12:35:47 -07:00
Alan Dipert
8f2a28a1f2 Fix #2624 by aligning select* input handling of groups with that of updateSelect* 2019-09-19 20:16:36 +00:00
Carson Sievert
e8fb1faec0 Merge pull request #2623 from rstudio/carson/rc-ci
Fix travis build for 1.4.0
2019-09-18 13:51:46 -05:00
Carson
0e4874c412 have appveyor run github versions as well 2019-09-18 13:36:22 -05:00
Carson
933630af28 Update stack call test expectation in light of https://github.com/rstudio/promises/commit/9ebad6#diff-1220ed154f06164c0a2d6cc053c1f3c1R134 2019-09-18 13:28:32 -05:00
Carson
ff87098102 Temporarily install rc branches to get Travis passing 2019-09-18 12:58:23 -05:00
Winston Chang
6513a86bbd Merge pull request #2621 from rstudio/carson/bugfix/avoid-offsetX
Use pageX/pageY instead of offsetX/offsetY
2019-09-18 12:42:58 -05:00
Carson
97e296c5d5 Use pageX/pageY instead of offsetX/offsetY to determine if a second click is too far away before triggering a double-click event. Closes #2620 2019-09-17 17:49:20 -05:00
Winston Chang
9f87adf4e8 Merge pull request #2619 from rstudio/wch/eslint-rules
Better checking for implicit globals in JS
2019-09-17 15:18:05 -05:00
Joe Cheng
6470b3f08c Fix 062-submitbutton-demo
1) In srcjs/input_rate.js line 284, the global variable `name` was
   being written to.
2) In a couple of other places in that file, the global variable
   `name` was being read instead of `nameType`--the result of an
   incomplete refactor.

Also added an eslint rule to prevent this and other globals from
being read implicitly.
2019-09-17 12:55:47 -07:00
Joe Cheng
d1ba84525e Update version number inserted by Grunt 2019-09-17 12:41:02 -07:00
Winston Chang
05ad66c464 Better checking for implicit globals 2019-09-17 14:09:11 -05:00
Winston Chang
c41d38bf61 Document insertUI() and removeUI() together
Since they share so many arguments. I also updated the style of the roxygen comments.
2019-09-17 07:55:53 -05:00
Hadley Wickham
b155e8480b Update docs 2019-09-16 12:30:50 -05:00
Hadley Wickham
e94f687573 Tweak shinyApp docs about bookmarking 2019-09-16 08:00:14 -05:00
Hadley Wickham
5883082d01 Improve inputFile() accept documentation
* accept should be a vector of "unique file type identifiers" not a vector of mime types (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#Unique_file_type_specifiers)

* I updated the example to use req() and to validate the uploaded extension; this is good practice since not all browsers will enforce `accept`
2019-09-15 09:07:16 -05:00
Hadley Wickham
75b53ffda1 Combine documentation for textOutput() and verbatimTextOutput()
And generally polish docs
2019-09-14 09:10:59 -05:00
Joe Cheng
a8057b96f3 Update version dependencies 2019-09-13 13:45:45 -07:00
Joe Cheng
a89e809498 Bump version to 1.4.0 2019-09-13 13:01:25 -07:00
Winston Chang
02f7a4fdc9 Rebuild documentation 2019-09-12 18:40:35 -05:00
Carson Sievert
7c7c22a597 Document default values of shiny's options (#2597)
* Document default values of shiny's options, closes #2558

* A more general description of shiny.port's default
2019-09-12 18:31:07 -05:00
Winston Chang
860fa525a2 Merge pull request #2605 from hadley/notification-id
Clarify use of id argument
2019-09-12 18:20:17 -05:00
Carson Sievert
9f0e38a28a Merge pull request #2601 from rstudio/layoutFamily
Layout Rd family
2019-09-12 13:09:00 -07:00
Jeff Allen
f834b7befb Define what all input functions yield for server (#2600)
* adding section to roxygen docs for server value of input funcs

* add more server values to roxygen docs

* add more server values

* update more server values in documentation

* Address PR feedback

I reflowed the comments to have a max width of 80 on some files, so there were a flurry of line changes, but the only substantive changes were around Joe's comments.

* Update R/input-slider.R

Co-Authored-By: Hadley Wickham <h.wickham@gmail.com>

* Apply suggestions from code review

Co-Authored-By: Carson Sievert <cpsievert1@gmail.com>

* PR feedback, regenerate docs.

* PR Feedback

* Eliminate extra newline

* passwordInput()'s server value

* varSelectInput()'s server value

* document
2019-09-12 20:02:44 +00:00
Winston Chang
7f3a45fb5b Merge pull request #2560 from rstudio/barret-reactlog-keybindings
Use ctrl/cmd + shift + f3 to mark reactlog and Return a 501 error code if reactlog disabled
2019-09-12 10:29:57 -05:00
Barret Schloerke
b0953e810b merge master 2019-09-12 10:26:38 -04:00
Hadley Wickham
52a86012e5 Update R/notifications.R
Co-Authored-By: Carson Sievert <cpsievert1@gmail.com>
2019-09-12 09:09:09 -05:00
Hadley Wickham
2a06fe6baf Clarify use of id argument 2019-09-12 08:28:27 -05:00
Carson
6e688d2175 add fillPage() to the family as well 2019-09-11 16:30:25 -05:00
Carson
b610fd1f56 Hadley's feedback 2019-09-11 16:29:48 -05:00
Carson
a4730096f4 code review 2019-09-11 15:23:41 -05:00
leslie-huang
6a02439944 add @ family to all layout functions 2019-09-11 15:15:38 -05:00
Carson Sievert
b889b0d2b0 Merge pull request #2582 from rstudio/barret_showcase_hidden_wide
Fix showcase bug where hidden by default on wide window
2019-09-11 10:59:18 -07:00
Carson
ba5733e4a4 add news item 2019-09-11 12:34:20 -05:00
Carson Sievert
2e0221ecfd Merge pull request #2592 from rstudio/set-min-max
Exit early if date parsing fails
2019-09-09 13:55:08 -07:00
Carson
aeded79544 yarn build 2019-09-09 15:43:41 -05:00
Carson
c0a7958e77 update news 2019-09-09 15:18:41 -05:00
Carson
431b194ec2 Exit early if date parsing fails in _setMin() and _setMax(), closes #2591 2019-09-09 13:48:18 -05:00
Joe Cheng
29d24d7e08 Merge pull request #2586 from rstudio/resourcePathChangesOption
Suppress resource path changes by default
2019-09-06 13:20:35 -07:00
Carson
6f9c621774 Always suppress for now 2019-09-05 17:22:56 -05:00
trestletech
324d9195c3 Merge remote-tracking branch 'origin/wch-slider-phantom' into jeff/feature/test 2019-09-05 16:51:49 -05:00
Carson
1c8071a96f Add shiny.resourcePathChanges option to get more information about resource path changes for a given prefix.
Closes #2584
2019-09-05 13:44:21 -05:00
trestletech
4ad115e024 Load the helpers before the tests -- into an ancestor environment of the tests'. 2019-09-05 09:46:34 -05:00
trestletech
f11d754cfe Add a filter to test 2019-09-05 09:45:06 -05:00
trestletech
65019ce96f Add namespace rewire option.
Return the right structure from shinytest tests and add unit tests.
2019-09-05 09:44:56 -05:00
trestletech
90e8fb2a57 Adding a test runner 2019-09-05 09:44:40 -05:00
Barret Schloerke
c0a7a6d0d6 don't hide the current element, instead make sure new element is hidden before fading in 2019-09-04 12:44:08 -04:00
Barret Schloerke
29c48471f2 hide the prior element, not the new element 2019-09-04 12:24:49 -04:00
Barret Schloerke
229e56464b if no code tab exists, do not attempt to highlight it 2019-09-04 12:24:20 -04:00
Barret Schloerke
1685e1c310 Merge branch 'master' into barret-reactlog-keybindings
* master: (22 commits)
  Fix upper-case test
  autload
  - update NEWS - only source global in server.R mode - only use intermediary environment if opted-in to autoloading.
  Only use loadSupport if opted-in to autload.r
  Fix default param
  Make loading helpers opt-in.
  Clarify docs
  Update to new signature in test.
  Move global.R sourcing into an exported load function
  Only load top-level R files in R/
  Require capitalized R/ dir.
  Correct mistake around app.R in global
  Add news
  Fix options test
  Test ui/server/app/global sourcing.
  Revert "DI the source function for testing."
  DI the source function for testing.
  Load helpers into isolated environment
  Fix expectations.
  Add dynamically-generated case-sensitive test.
  ...
2019-08-28 12:26:39 -04:00
Barret Schloerke
332f5a1266 add js for opening broken reactlog routes 2019-08-28 12:24:17 -04:00
Barret Schloerke
68d67a8194 Update NEWS.md 2019-08-27 17:51:10 -04:00
Barret Schloerke
756ac1514c Use ctrl/cmd + shift + f3 to mark reactlog; return a 501 error code for reactlog paths when reactlog is disabled
Open a new webpage even if only marking a time.
2019-08-27 17:50:46 -04:00
238 changed files with 21511 additions and 4581 deletions

View File

@@ -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:

View File

@@ -5,26 +5,28 @@ matrix:
r: release
r_packages:
- devtools
- roxygen2
script: ./tools/checkDocsCurrent.sh
- rprojroot
script: ./tools/documentation/checkDocsCurrent.sh
env:
# GITHUB_PAT for gh::gh calls
- secure: "Hk4piVNtDobLT1dQPnCOcM7sOlwNGJOU5cpvbRvOxYSgxP+Bj2MyRZMe825rdHkHbFez0h8w3tJOBf9DDBH7PC1BhhNll2+WM/WxGlkNleg8vsoH/Xopffl+2YgtWbAYZjQ2j0QYdgNn0e/TY86/ggk9qit6+gpsZ7z/HmWQuVY="
- 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:
email:
on_success: change
on_failure: change
slack:
secure: QoM0+hliVC4l2HYv126AkljG/uFvgwayW9IpuB5QNqjSukM122MhMDL7ZuMB9a2vWP24juzOTXiNIymgEspfnvvAMnZwYRBNWkuot2m8HIR2B9UjQLiztFnN1EAT+P+thz8Qax9TV2SOfXb2S2ZOeZmRTVkJctxkL8heAZadIC4=
on_pull_requests: false

View File

@@ -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,23 @@ Depends:
Imports:
utils,
grDevices,
httpuv (>= 1.5.1.9002),
httpuv (>= 1.5.2),
mime (>= 0.3),
jsonlite (>= 0.9.16),
xtable,
digest,
htmltools (>= 0.3.6.9004),
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 (>= 1.0.0)
fastmap (>= 1.0.0),
withr,
commonmark (>= 1.7),
glue (>= 1.3.2)
Suggests:
datasets,
Cairo (>= 1.5-5),
@@ -88,14 +91,18 @@ Suggests:
rmarkdown,
ggplot2,
reactlog (>= 1.0.0),
magrittr
magrittr,
shinytest,
yaml,
future,
dygraphs
Remotes:
rstudio/htmltools,
rstudio/httpuv
rstudio/htmltools
URL: http://shiny.rstudio.com
BugReports: https://github.com/rstudio/shiny/issues
Collate:
'app.R'
'app_template.R'
'bookmark-state-local.R'
'stack.R'
'bookmark-state.R'
@@ -143,12 +150,15 @@ Collate:
'jqueryui.R'
'middleware-shiny.R'
'middleware.R'
'timer.R'
'mock-session.R'
'modal.R'
'modules.R'
'notifications.R'
'priorityqueue.R'
'progress.R'
'react.R'
'reexports.R'
'render-cached-plot.R'
'render-plot.R'
'render-table.R'
@@ -164,8 +174,9 @@ Collate:
'snapshot.R'
'tar.R'
'test-export.R'
'timer.R'
'test-server.R'
'test.R'
'update-input.R'
RoxygenNote: 6.1.1
RoxygenNote: 7.1.0
Encoding: UTF-8
Roxygen: list(markdown = TRUE)

View File

@@ -1,15 +1,18 @@
# Generated by roxygen2: do not edit by hand
S3method("$",mockclientdata)
S3method("$",reactivevalues)
S3method("$",session_proxy)
S3method("$",shinyoutput)
S3method("$<-",reactivevalues)
S3method("$<-",session_proxy)
S3method("$<-",shinyoutput)
S3method("[",mockclientdata)
S3method("[",reactivevalues)
S3method("[",shinyoutput)
S3method("[<-",reactivevalues)
S3method("[<-",shinyoutput)
S3method("[[",mockclientdata)
S3method("[[",reactivevalues)
S3method("[[",session_proxy)
S3method("[[",shinyoutput)
@@ -34,6 +37,7 @@ export("conditionStackTrace<-")
export(..stacktraceoff..)
export(..stacktraceon..)
export(HTML)
export(MockShinySession)
export(NS)
export(Progress)
export(a)
@@ -138,10 +142,12 @@ export(loadSupport)
export(mainPanel)
export(makeReactiveBinding)
export(markRenderFunction)
export(markdown)
export(maskReactiveContext)
export(memoryCache)
export(modalButton)
export(modalDialog)
export(moduleServer)
export(navbarMenu)
export(navbarPage)
export(navlistPanel)
@@ -212,6 +218,7 @@ export(runExample)
export(runGadget)
export(runGist)
export(runGitHub)
export(runTests)
export(runUrl)
export(safeError)
export(selectInput)
@@ -223,6 +230,7 @@ export(setSerializer)
export(shinyApp)
export(shinyAppDir)
export(shinyAppFile)
export(shinyAppTemplate)
export(shinyOptions)
export(shinyServer)
export(shinyUI)
@@ -257,6 +265,7 @@ export(tagHasAttribute)
export(tagList)
export(tagSetChildren)
export(tags)
export(testServer)
export(textAreaInput)
export(textInput)
export(textOutput)
@@ -306,3 +315,44 @@ importFrom(fastmap,is.key_missing)
importFrom(fastmap,key_missing)
importFrom(grDevices,dev.cur)
importFrom(grDevices,dev.set)
importFrom(htmltools,HTML)
importFrom(htmltools,a)
importFrom(htmltools,br)
importFrom(htmltools,code)
importFrom(htmltools,div)
importFrom(htmltools,em)
importFrom(htmltools,h1)
importFrom(htmltools,h2)
importFrom(htmltools,h3)
importFrom(htmltools,h4)
importFrom(htmltools,h5)
importFrom(htmltools,h6)
importFrom(htmltools,hr)
importFrom(htmltools,htmlTemplate)
importFrom(htmltools,img)
importFrom(htmltools,includeCSS)
importFrom(htmltools,includeHTML)
importFrom(htmltools,includeMarkdown)
importFrom(htmltools,includeScript)
importFrom(htmltools,includeText)
importFrom(htmltools,is.singleton)
importFrom(htmltools,p)
importFrom(htmltools,pre)
importFrom(htmltools,singleton)
importFrom(htmltools,span)
importFrom(htmltools,strong)
importFrom(htmltools,suppressDependencies)
importFrom(htmltools,tag)
importFrom(htmltools,tagAppendAttributes)
importFrom(htmltools,tagAppendChild)
importFrom(htmltools,tagAppendChildren)
importFrom(htmltools,tagGetAttribute)
importFrom(htmltools,tagHasAttribute)
importFrom(htmltools,tagList)
importFrom(htmltools,tagSetChildren)
importFrom(htmltools,tags)
importFrom(htmltools,validateCssUnit)
importFrom(htmltools,withTags)
importFrom(promises,"%...!%")
importFrom(promises,"%...>%")
importFrom(rlang,env_clone)

99
NEWS.md
View File

@@ -1,41 +1,96 @@
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
* `runTests()` is a new function that behaves much like R CMD check. `runTests()` invokes all of the top-level R files in the tests/ directory inside an application, in that application's environment. ([#2585](https://github.com/rstudio/shiny/pull/2585))
* `testServer()` and `testModule()` are two new functions for testing reactive behavior inside server functions and modules, respectively. ([#2682](https://github.com/rstudio/shiny/pull/2682), [#2764](https://github.com/rstudio/shiny/pull/2764))
* The new `moduleServer` function provides a simpler interface for creating and using modules. ([#2773](https://github.com/rstudio/shiny/pull/2773))
* Resolved [#2732](https://github.com/rstudio/shiny/issues/2732): `markdown()` is a new function for writing Markdown with Github extensions directly in Shiny UIs. Markdown rendering is performed by the [commonmark](https://github.com/jeroen/commonmark) package. ([#2737](https://github.com/rstudio/shiny/pull/2737))
### 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.2
===========
Minor patch release: fixed some timing-dependent tests failed intermittently on CRAN build machines.
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))
* Resolved [#2469](https://github.com/rstudio/shiny/issues/2469): `renderText` now takes a `sep` argument that is passed to `cat`. ([#2497](https://github.com/rstudio/shiny/pull/2497))
* Added `resourcePaths()` and `removeResourcePaths()` functions. ([#2459](https://github.com/rstudio/shiny/pull/2459))
* Resolved [#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)
* 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))
* 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))
* Added `resourcePaths()` and `removeResourcePaths()` functions. ([#2459](https://github.com/rstudio/shiny/pull/2459))
* Resolved [#2515](https://github.com/rstudio/shiny/issues/2515): `selectInput()` now deals appropriately with named factors. ([#2524](https://github.com/rstudio/shiny/pull/2524))
* Resolved [#2433](https://github.com/rstudio/shiny/issues/2433): An informative warning is now thrown if subdirectories of the app's `www/` directory are masked by other resource prefixes and/or the same resource prefix is mapped to different local file paths. ([#2434](https://github.com/rstudio/shiny/pull/2434))
* Resolved [#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))
### Bug fixes
* Fixed [#2116](https://github.com/rstudio/shiny/issues/2116): Fixed an issue where dynamic tabs could not be added when on a hosted platform. ([#2545](https://github.com/rstudio/shiny/pull/2545))
* Fixed [#2387](https://github.com/rstudio/shiny/issues/2387): Updating a `sliderInput()`'s type from numeric to date no longer changes the rate policy from debounced to immediate. More generally, updating an input binding with a new type should (no longer) incorrectly alter the input rate policy. ([#2404](https://github.com/rstudio/shiny/pull/2404))
* Fixed [#868](https://github.com/rstudio/shiny/issues/868): If an input is initialized with a `NULL` label, it can now be updated with a string. Moreover, if an input label is initialized with a string, it can now be removed by updating with `label=character(0)` (similar to how `choices` and `selected` can be cleared in `updateSelectInput()`). ([#2406](https://github.com/rstudio/shiny/pull/2406))
@@ -46,23 +101,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 [#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.
### Library updates
* Resolved [#2554](https://github.com/rstudio/shiny/issues/2554): Upgraded bootstrap to v3.4.1 and jQuery to v3.4.1. ([#2557](https://github.com/rstudio/shiny/pull/2557))
shiny 1.3.2
===========
### 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))
@@ -626,7 +681,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%"/>

57
R/app.R
View File

@@ -13,7 +13,10 @@
#' object to `print()` or [runApp()].
#'
#' @param ui The UI definition of the app (for example, a call to
#' `fluidPage()` with nested controls)
#' `fluidPage()` with nested controls).
#'
#' If bookmarking is enabled (see `enableBookmarking`), this must be
#' a single argument function that returns the UI definition.
#' @param server A function with three parameters: `input`, `output`, and
#' `session`. The function is called once for each session ensuring that each
#' app is independent.
@@ -30,11 +33,9 @@
#' request. Note that the entire request path must match the regular
#' expression in order for the match to be considered successful.
#' @param enableBookmarking Can be one of `"url"`, `"server"`, or
#' `"disable"`. This is equivalent to calling the
#' [enableBookmarking()] function just before calling
#' `shinyApp()`. With the default value (`NULL`), the app will
#' respect the setting from any previous calls to `enableBookmarking()`.
#' See [enableBookmarking()] for more information.
#' `"disable"`. The default value, `NULL`, will respect the setting from
#' any previous calls to [enableBookmarking()]. See [enableBookmarking()]
#' for more information on bookmarking your app.
#' @return An object that represents the app. Printing the object or passing it
#' to [runApp()] will run the app.
#'
@@ -146,15 +147,13 @@ shinyAppDir_serverR <- function(appDir, options=list()) {
# Most of the complexity here comes from needing to hot-reload if the .R files
# change on disk, or are created, or are removed.
# In an upcoming version of shiny, this option will go away and the new behavior will be used.
if (getOption("shiny.autoload.r", FALSE)) {
# new behavior
# 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, default
# old behavior
sharedEnv <- globalenv()
}
@@ -230,7 +229,7 @@ shinyAppDir_serverR <- function(appDir, options=list()) {
setwd(appDir)
monitorHandle <<- initAutoReloadMonitor(appDir)
# TODO: we should support hot reloading on global.R and R/*.R changes.
if (getOption("shiny.autoload.r", FALSE)) {
if (getOption("shiny.autoload.r", TRUE)) {
loadSupport(appDir, renv=sharedEnv, globalrenv=globalenv())
} else {
if (file.exists(file.path.ci(appDir, "global.R")))
@@ -285,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
@@ -314,8 +314,13 @@ initAutoReloadMonitor <- function(dir) {
#' this function loads any top-level supporting `.R` files in the `R/` directory
#' adjacent to the `app.R`/`server.R`/`ui.R` files.
#'
#' At the moment, this function is "opt-in" and only called if the option
#' `shiny.autoload.r` is set to `TRUE`.
#' 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
@@ -335,8 +340,21 @@ loadSupport <- function(appDir, renv=new.env(parent=globalenv()), globalrenv=glo
}
helpersDir <- file.path(appDir, "R")
disabled <- list.files(helpersDir, pattern="^_disable_autoload\\.r$", recursive=FALSE, ignore.case=TRUE)
if (length(disabled) > 0){
message("R/_disable_autoload.R detected; not loading the R/ directory automatically")
return(invisible(renv))
}
helpers <- list.files(helpersDir, pattern="\\.[rR]$", recursive=FALSE, full.names=TRUE)
if (length(helpers) > 0){
message("Automatically loading ", length(helpers), " .R file",
ifelse(length(helpers) != 1, "s", ""),
" found in the R/ directory.\nSee https://rstd.io/shiny-autoload for more info.")
}
lapply(helpers, sourceUTF8, envir=renv)
invisible(renv)
@@ -349,15 +367,12 @@ shinyAppDir_appR <- function(fileName, appDir, options=list())
{
fullpath <- file.path.ci(appDir, fileName)
# In an upcoming version of shiny, this option will go away and the new behavior will be used.
if (getOption("shiny.autoload.r", FALSE)) {
# new behavior
# 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, default
sharedEnv <- globalenv()
}
@@ -411,7 +426,7 @@ shinyAppDir_appR <- function(fileName, appDir, options=list())
oldwd <<- getwd()
setwd(appDir)
# TODO: we should support hot reloading on R/*.R changes.
if (getOption("shiny.autoload.r", FALSE)) {
if (getOption("shiny.autoload.r", TRUE)) {
loadSupport(appDir, renv=sharedEnv, globalrenv=NULL)
}
monitorHandle <<- initAutoReloadMonitor(appDir)

259
R/app_template.R Normal file
View File

@@ -0,0 +1,259 @@
#' Generate a Shiny application from a template
#'
#' This function populates a directory with files for a Shiny application. They
#' are based off of the "12_counter" example which can be run with
#' `runExample()`.
#'
#' In an interactive R session, this function will, by default, prompt the user
#' which components to add to the application.
#'
#' The full example application includes the following files and directories:
#'
#' ```
#' appdir/
#' ├── app.R
#' ├── R
#' │ ├── my-module.R
#' │ └── utils.R
#' └── tests
#' ├── server.R
#' ├── server
#' │ ├── test-mymodule.R
#' │ └── test-server.R
#' ├── shinytest.R
#' ├── shinytest
#' │ └── mytest.R
#' ├── testthat.R
#' └── testthat
#' ├── helper-load.R
#' └── test-utils.R
#' ```
#'
#' Some notes about these files:
#' * app.R is the main application file.
#' * All files in the R/ subdirectory are automatically sourced when the
#' application is run.
#' * The R/my-module.R file is automatically sourced when the application
#' is run. This file contains code for a [Shiny module](moduleServer()) which
#' is used in the application.
#' * The tests/ directory contains various tests for the application. You may
#' choose to use or remove any of them. They can be executed by the
#' [runTests()] function.
#' * tests/server.R is a test runner for test files in
#' tests/server/.
#' * tests/server/test-mymodule.R is a test for the module.
#' * tests/shinytest.R is a test runner for test files in the
#' tests/shinytest/ directory.
#' * tests/shinytest/mytest.R is a test that uses the
#' [shinytest](https://rstudio.github.io/shinytest/) package to do
#' snapshot-based testing.
#' * tests/testthat.R is a test runner for test files in the
#' tests/testthat/ directory.
#' * tests/testthat/helper-load.R is a helper script that is automatically
#' loaded before running test-counter.R. (This is performed by the testthat
#' package.)
#' * tests/testthat/test-utils.R is a set of tests that use the
#' [testthat](https://testthat.r-lib.org/) package for testing.
#'
#' @param path Path to create new shiny application template.
#' @param examples Either one of "default", "ask", "all", or any combination of
#' "app", "rdir", "module", "shinytest", "testthat", and "server". In an
#' interactive session, "default" falls back to "ask"; in a non-interactive
#' session, "default" falls back to "all". With "ask", this function will
#' prompt the user to select which template items will be added to the new app
#' directory. With "all", all template items will be added to the app
#' directory.
#'
#' @export
shinyAppTemplate <- function(path = NULL, examples = "default")
{
choices <- c(
app = "app.R : Main application file",
rdir = "R/utils.R : Helper file with R code",
module = "R/my-module.R : Example module",
shinytest = "tests/shinytest/ : Tests using shinytest package",
testthat = "tests/testthat/ : Tests using testthat",
server = "tests/server/ : Tests of server and module code"
)
if (length(examples) == 1 && examples == "default") {
if (interactive()) {
examples <- "ask"
} else {
examples <- "all"
}
}
if (!identical(examples, "ask") &&
!identical(examples, "all") &&
any(! examples %in% names(choices)))
{
stop('`examples` must be one of "default", "ask", "all", or any combination of "',
paste(names(choices), collapse = '", "'), '".')
}
if (identical(examples, "ask")) {
response <- select_menu(
c(all = "All", choices),
title = paste0(
"Select which of the following to add at ", path, "/ :"
),
msg = "Enter one or more numbers (with spaces), or an empty line to exit: \n"
)
examples <- names(response)
}
if ("all" %in% examples) {
examples <- names(choices)
}
if (length(examples) == 0) {
return(invisible())
}
# Check if a directory is empty, ignoring certain files
dir_is_empty <- function(path) {
files <- list.files(path, all.files = TRUE, no.. = TRUE)
# Ignore .DS_Store files, which are sometimes automatically created on macOS
files <- setdiff(files, ".DS_Store")
return(length(files) != 0)
}
# Helper to resolve paths relative to our example
example_path <- function(path) {
system.file("examples", "12_counter", path, package = "shiny")
}
# Helper to remove rdir code from a file
remove_rdir_code <- function(filename) {
txt <- readLines(filename)
txt <- txt[!grepl("# lexical_sort from R/utils.R", txt)]
txt <- sub("Lexically sorted sequence", "Sorted sequence", txt, fixed = TRUE)
txt <- sub("lexical_sort", "sort", txt, fixed = TRUE)
# Write with \n line endings on all platforms
con <- file(filename, open="wb")
writeLines(txt, con)
close(con)
}
# Helper to remove module code from a file
remove_module_code <- function(filename) {
txt <- readLines(filename)
start_lines <- grep("^ +# =+ Modules =+$", txt)
stop_lines <- grep("^ +# =+$", txt)
if (length(start_lines) != length(stop_lines)) {
stop("Start and end markers are unbalanced.")
}
if (length(start_lines) == 0) {
return()
}
drop_lines <- unlist(lapply(seq_along(start_lines), function(i) {
seq(start_lines[i], stop_lines[i])
}))
# Write with \n line endings on all platforms
con <- file(filename, open="wb")
writeLines(txt[-drop_lines], con)
close(con)
}
# Copy the files for a tests/ subdirectory
copy_test_dir <- function(name, with_rdir, with_module) {
tests_dir <- file.path(path, "tests")
if (!dirExists(tests_dir)) {
dir.create(tests_dir, recursive = TRUE)
}
files <- dir(example_path("tests"), recursive = TRUE)
# Note: This is not the same as using dir(pattern = "^shinytest"), since
# that will not match files inside of shinytest/.
files <- files[grepl(paste0("^", name), files)]
# Filter out files related to R/utils.R, if applicable.
if (!with_rdir) {
files <- files[!grepl("utils", files)]
}
# Filter out module files, if applicable.
if (!with_module) {
files <- files[!grepl("module", files)]
}
# Create any subdirectories if needed
dirs <- setdiff(unique(dirname(files)), ".")
for (dir in dirs) {
dir.create(file.path(tests_dir, dir), recursive = TRUE)
}
file.copy(
file.path(example_path("tests"), files),
file.path(path, "tests", files)
)
}
if (is.null(path)) {
stop("`path` is missing.")
}
if (file.exists(path) && !dir.exists(path)) {
stop(path, " exists but is not a directory.")
}
if (dir.exists(path) && dir_is_empty(path)) {
if (interactive()) {
response <- readline(paste0(
ensure_trailing_slash(path),
" is not empty. Do you want to create a Shiny app in this directory anyway? [y/n] "
))
if (tolower(response) != "y") {
return(invisible())
}
}
} else {
dir.create(path)
}
# app.R - If "app", populate with example; otherwise use empty file.
app_file <- file.path(path, "app.R")
if ("app" %in% examples) {
if (file.exists(app_file)) {
message(app_file, " already exists")
}
file.copy(example_path("app.R"), path)
if (!"rdir" %in% examples) {
remove_rdir_code(app_file)
}
if (!"module" %in% examples) {
remove_module_code(app_file)
}
}
# R/ dir with utils and/or module
r_dir <- file.path(path, "R")
if ("rdir" %in% examples) {
if (!dirExists(r_dir)) {
dir.create(r_dir, recursive = TRUE)
}
file.copy(example_path("R/utils.R"), r_dir, recursive = TRUE)
}
if ("module" %in% examples) {
if (!dirExists(r_dir)) {
dir.create(r_dir, recursive = TRUE)
}
file.copy(example_path("R/my-module.R"), r_dir, recursive = TRUE)
}
# tests/ dir
if ("shinytest" %in% examples) {
copy_test_dir("shinytest", "rdir" %in% examples, "module" %in% examples)
}
if ("testthat" %in% examples) {
copy_test_dir("testthat", "rdir" %in% examples, "module" %in% examples)
}
if ("server" %in% examples) {
copy_test_dir("server", "rdir" %in% examples, "module" %in% examples)
}
if ("app" %in% examples) {
message("Shiny application created at ", ensure_trailing_slash(path))
}
}

View File

@@ -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()) {
@@ -279,6 +285,8 @@ titlePanel <- function(title, windowTitle=title) {
#' 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
#' if (interactive()) {
@@ -369,7 +377,7 @@ mainPanel <- function(..., width = 8) {
#' @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
@@ -407,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
@@ -463,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()) {
@@ -560,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

View File

@@ -103,7 +103,7 @@ basicPage <- function(...) {
#' *automatic* height; that is, they determine their own height based on
#' the height of their contained elements. However,
#' `fillPage(plotOutput("plot", height = "100%"))` will work because
#' `fillPage` fixes the `<body>` height at 100\% of the window height.
#' `fillPage` fixes the `<body>` height at 100% of the window height.
#'
#' Note that `fillPage(plotOutput("plot"))` will not cause the plot to fill
#' the page. Like most Shiny output widgets, `plotOutput`'s default height
@@ -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",
@@ -233,6 +235,8 @@ collapseSizes <- function(padding) {
#' [updateNavbarPage()], [insertTab()],
#' [showTab()]
#'
#' @family layout functions
#'
#' @examples
#' navbarPage("App Title",
#' tabPanel("Plot"),
@@ -789,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"),

View File

@@ -1,11 +1,3 @@
#' @importFrom fastmap key_missing
#' @export
fastmap::key_missing
#' @importFrom fastmap is.key_missing
#' @export
fastmap::is.key_missing
validate_key <- function(key) {
if (!is.character(key) || length(key) != 1 || nchar(key) == 0) {
@@ -15,4 +7,3 @@ validate_key <- function(key) {
stop("Invalid key: ", key, ". Only lowercase letters and numbers are allowed.")
}
}

View File

@@ -16,7 +16,9 @@ register_s3_method <- function(pkg, generic, class, fun = NULL) {
registerS3method(generic, class, fun, envir = asNamespace(pkg))
}
# Always register hook in case package is later unloaded & reloaded
# 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(...) {
@@ -25,6 +27,37 @@ register_s3_method <- function(pkg, generic, class, fun = NULL) {
)
}
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
@@ -36,18 +69,10 @@ register_s3_method <- function(pkg, generic, class, fun = NULL) {
register_s3_method("knitr", "knit_print", "reactive")
register_s3_method("knitr", "knit_print", "shiny.appobj")
register_s3_method("knitr", "knit_print", "shiny.render.function")
}
.onAttach <- function(libname, pkgname) {
# 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."
)
}
# 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)
}

View File

@@ -16,7 +16,7 @@
#'
#' ui <- fluidPage(
#' sliderInput("obs", "Number of observations", 0, 1000, 500),
#' actionButton("goButton", "Go!"),
#' actionButton("goButton", "Go!", class = "btn-success"),
#' plotOutput("distPlot")
#' )
#'
@@ -36,7 +36,18 @@
#'
#' }
#'
#' ## Example of adding extra class values
#' actionButton("largeButton", "Large Primary Button", class = "btn-primary btn-lg")
#' actionLink("infoLink", "Information Link", class = "btn-info")
#'
#' @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, ...) {

View File

@@ -22,6 +22,10 @@
#' }
#' shinyApp(ui, server)
#' }
#'
#' @section Server value:
#' `TRUE` if checked, `FALSE` otherwise.
#'
#' @export
checkboxInput <- function(inputId, label, value = FALSE, width = NULL) {

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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,

View File

@@ -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")
)
)

View File

@@ -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) {

View File

@@ -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()) {

View File

@@ -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) {

View File

@@ -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

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -92,7 +92,10 @@ generateOptions <- function(inputId, selected, inline, type = 'checkbox',
# True when a choice list item represents a group of related inputs.
isGroup <- function(choice) {
length(choice) > 1 || !is.null(names(choice))
is.list(choice) ||
!is.null(names(choice)) ||
length(choice) > 1 ||
length(choice) == 0
}
# True when choices is a list and contains at least one group of related inputs.
@@ -131,6 +134,10 @@ processFlatChoices <- function(choices) {
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 == "") {

View File

@@ -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,

View File

@@ -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)
}
}

461
R/mock-session.R Normal file
View File

@@ -0,0 +1,461 @@
# 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.")
}
#' @noRd
mapNames <- function(func, ...) {
vals <- list(...)
names(vals) <- vapply(names(vals), func, character(1))
vals
}
#' 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 returned The value returned by the module.
returned = 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 this namespace's id.
#' @param id The id to modify.
ns = function(id) {
NS(private$nsPrefix, id)
},
#' @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)),
ns = function(namespace) ns(namespace),
setInputs = function(...) do.call(self$setInputs, mapNames(ns, ...))
)
},
#' @description Set the environment associated with a testServer() call, but
#' only if it has not previously been set. This ensures that only the
#' environment of the outermost module under test is the one retained. In
#' other words, the first assignment wins.
#' @param env The environment to retain.
setEnv = function(env) {
if (is.null(self$env)) self$env <- env
},
#' @description Set the value returned by the module call and proactively
#' flush. Note that this method may be called multiple times if modules
#' are nested. The last assignment, corresponding to an invocation of
#' setReturned() in the outermost module, wins.
#' @param value The value returned from the module
setReturned = function(value) {
self$returned <- value
private$flush()
value
},
#' @description Get the value returned by the module call.
getReturned = function() self$returned,
#' @description Return a distinct character identifier for use as a proxy
#' namespace.
genId = function() {
private$idCounter <- private$idCounter + 1
paste0("proxy", private$idCounter)
}
),
private = list(
.input = NULL,
flushCBs = NULL,
flushedCBs = NULL,
endedCBs = NULL,
timer = NULL,
closed = FALSE,
outs = list(),
nsPrefix = "mock-session",
idCounter = 0,
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(
#' @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())
}
)
)

View File

@@ -36,25 +36,117 @@ 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 `moduleServer` instead of
#' `callModule`, because the syntax is a little easier to understand, and
#' modules created with `moduleServer` can be tested with [`testServer()`].
#'
#' @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()) {
if (inherits(session, "MockShinySession")) {
body(module) <- rlang::expr({
session$setEnv(base::environment())
session$setReturned({ !!!body(module) })
})
}
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, {

View File

@@ -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
}

View File

@@ -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.")

View File

@@ -222,7 +222,7 @@ reactiveVal <- function(value = NULL, label = NULL) {
rv$set(x)
}
},
class = c("reactiveVal", "reactive"),
class = c("reactiveVal", "reactive", "function"),
label = label,
.impl = rv
)
@@ -969,7 +969,7 @@ reactive <- function(x, env = parent.frame(), quoted = FALSE, label = NULL,
if (length(srcref) >= 2) attr(label, "srcref") <- srcref[[2]]
attr(label, "srcfile") <- srcFileOfRef(srcref[[1]])
o <- Observable$new(fun, label, domain, ..stacktraceon = ..stacktraceon)
structure(o$getValue, observable = o, class = c("reactiveExpr", "reactive"))
structure(o$getValue, observable = o, class = c("reactiveExpr", "reactive", "function"))
}
# Given the srcref to a reactive expression, attempts to figure out what the
@@ -1513,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(
@@ -1613,7 +1615,6 @@ reactiveTimer <- function(intervalMs=1000, session = getDefaultReactiveDomain())
#' }
#' @export
invalidateLater <- function(millis, session = getDefaultReactiveDomain()) {
force(session)
ctx <- getCurrentContext()
@@ -1621,7 +1622,9 @@ invalidateLater <- function(millis, session = getDefaultReactiveDomain()) {
clear_on_ended_callback <- function() {}
timerHandle <- scheduleTask(millis, function() {
scheduler <- defineScheduler(session)
timerHandle <- scheduler(millis, function() {
if (is.null(session)) {
ctx$invalidate()
return(invisible())
@@ -2359,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
@@ -2381,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)
@@ -2432,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

195
R/reexports.R Normal file
View File

@@ -0,0 +1,195 @@
####
# Generated by `./tools/updateReexports.R`: do not edit by hand
# Please call `source('tools/updateReexports.R') from the root folder to update`
####
# fastmap key_missing.Rd -------------------------------------------------------
#' @importFrom fastmap key_missing
#' @export
fastmap::key_missing
#' @importFrom fastmap is.key_missing
#' @export
fastmap::is.key_missing
# htmltools builder.Rd ---------------------------------------------------------
#' @importFrom htmltools tags
#' @export
htmltools::tags
#' @importFrom htmltools p
#' @export
htmltools::p
#' @importFrom htmltools h1
#' @export
htmltools::h1
#' @importFrom htmltools h2
#' @export
htmltools::h2
#' @importFrom htmltools h3
#' @export
htmltools::h3
#' @importFrom htmltools h4
#' @export
htmltools::h4
#' @importFrom htmltools h5
#' @export
htmltools::h5
#' @importFrom htmltools h6
#' @export
htmltools::h6
#' @importFrom htmltools a
#' @export
htmltools::a
#' @importFrom htmltools br
#' @export
htmltools::br
#' @importFrom htmltools div
#' @export
htmltools::div
#' @importFrom htmltools span
#' @export
htmltools::span
#' @importFrom htmltools pre
#' @export
htmltools::pre
#' @importFrom htmltools code
#' @export
htmltools::code
#' @importFrom htmltools img
#' @export
htmltools::img
#' @importFrom htmltools strong
#' @export
htmltools::strong
#' @importFrom htmltools em
#' @export
htmltools::em
#' @importFrom htmltools hr
#' @export
htmltools::hr
# htmltools tag.Rd -------------------------------------------------------------
#' @importFrom htmltools tag
#' @export
htmltools::tag
#' @importFrom htmltools tagList
#' @export
htmltools::tagList
#' @importFrom htmltools tagAppendAttributes
#' @export
htmltools::tagAppendAttributes
#' @importFrom htmltools tagHasAttribute
#' @export
htmltools::tagHasAttribute
#' @importFrom htmltools tagGetAttribute
#' @export
htmltools::tagGetAttribute
#' @importFrom htmltools tagAppendChild
#' @export
htmltools::tagAppendChild
#' @importFrom htmltools tagAppendChildren
#' @export
htmltools::tagAppendChildren
#' @importFrom htmltools tagSetChildren
#' @export
htmltools::tagSetChildren
# htmltools HTML.Rd ------------------------------------------------------------
#' @importFrom htmltools HTML
#' @export
htmltools::HTML
# htmltools include.Rd ---------------------------------------------------------
#' @importFrom htmltools includeHTML
#' @export
htmltools::includeHTML
#' @importFrom htmltools includeText
#' @export
htmltools::includeText
#' @importFrom htmltools includeMarkdown
#' @export
htmltools::includeMarkdown
#' @importFrom htmltools includeCSS
#' @export
htmltools::includeCSS
#' @importFrom htmltools includeScript
#' @export
htmltools::includeScript
# htmltools singleton.Rd -------------------------------------------------------
#' @importFrom htmltools singleton
#' @export
htmltools::singleton
#' @importFrom htmltools is.singleton
#' @export
htmltools::is.singleton
# htmltools validateCssUnit.Rd -------------------------------------------------
#' @importFrom htmltools validateCssUnit
#' @export
htmltools::validateCssUnit
# htmltools htmlTemplate.Rd ----------------------------------------------------
#' @importFrom htmltools htmlTemplate
#' @export
htmltools::htmlTemplate
# htmltools suppressDependencies.Rd --------------------------------------------
#' @importFrom htmltools suppressDependencies
#' @export
htmltools::suppressDependencies
# htmltools withTags.Rd --------------------------------------------------------
#' @importFrom htmltools withTags
#' @export
htmltools::withTags

View File

@@ -889,6 +889,14 @@ find_panel_info_non_api <- function(b, ggplot_format) {
})
}
# Use public API for getting the unit's type (grid::unitType(), added in R 4.0)
# https://github.com/wch/r-source/blob/f9b8a42/src/library/grid/R/unit.R#L179
getUnitType <- function(u) {
tryCatch(
get("unitType", envir = asNamespace("grid"))(u),
error = function(e) attr(u, "unit", exact = TRUE)
)
}
# Given a gtable object, return the x and y ranges (in pixel dimensions)
find_panel_ranges <- function(g, res) {
@@ -904,11 +912,11 @@ find_panel_ranges <- function(g, res) {
if (inherits(x, "unit.list")) {
# For ggplot2 <= 1.0.1
vapply(x, FUN.VALUE = logical(1), function(u) {
isTRUE(attr(u, "unit", exact = TRUE) == "null")
isTRUE(getUnitType(u) == "null")
})
} else {
# For later versions of ggplot2
attr(x, "unit", exact = TRUE) == "null"
getUnitType(x) == "null"
}
}
@@ -948,7 +956,11 @@ find_panel_ranges <- function(g, res) {
# The plotting panels all are 'null' units.
null_sizes <- rep(NA_real_, length(rel_sizes))
null_sizes[null_idx] <- as.numeric(rel_sizes[null_idx])
# Workaround for `[.unit` forbidding zero-length subsets
# https://github.com/wch/r-source/blob/f9b8a42/src/library/grid/R/unit.R#L448-L450
if (length(null_idx)) {
null_sizes[null_idx] <- as.numeric(rel_sizes[null_idx])
}
# Total size allocated for panels is the total image size minus absolute
# (non-panel) elements.

View File

@@ -85,24 +85,25 @@ 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 comprimise is to throw a more information message.
if (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."
)
}
}
# # 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.
@@ -1229,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)
}

View File

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

View File

@@ -723,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
},
@@ -956,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)
@@ -1291,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)
@@ -2090,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
@@ -2281,3 +2296,56 @@ ShinyServerTimingRecorder <- R6Class("ShinyServerTimingRecorder",
)
missingOutput <- function(...) req(FALSE)
#' Insert inline Markdown
#'
#' This function accepts
#' [Markdown](https://en.wikipedia.org/wiki/Markdown)-syntax text and returns
#' HTML that may be included in Shiny UIs.
#'
#' Leading whitespace is trimmed from Markdown text with [glue::trim()].
#' Whitespace trimming ensures Markdown is processed correctly even when the
#' call to `markdown()` is indented within surrounding R code.
#'
#' By default, [Github extensions][commonmark::extensions] are enabled, but this
#' can be disabled by passing `extensions = FALSE`.
#'
#' Markdown rendering is performed by [commonmark::markdown_html()]. Additional
#' arguments to `markdown()` are passed as arguments to `markdown_html()`
#'
#' @param mds A character vector of Markdown source to convert to HTML. If the
#' vector has more than one element, a single-element character vector of
#' concatenated HTML is returned.
#' @param extensions Enable Github syntax extensions; defaults to `TRUE`.
#' @param .noWS Character vector used to omit some of the whitespace that would
#' normally be written around generated HTML. Valid options include `before`,
#' `after`, and `outside` (equivalent to `before` and `end`).
#' @param ... Additional arguments to pass to [commonmark::markdown_html()].
#' These arguments are _[dynamic][rlang::dyn-dots]_.
#'
#' @return a character vector marked as HTML.
#' @export
#' @examples
#' ui <- fluidPage(
#' markdown("
#' # Markdown Example
#'
#' This is a markdown paragraph, and will be contained within a `<p>` tag
#' in the UI.
#'
#' The following is an unordered list, which will be represented in the UI as
#' a `<ul>` with `<li>` children:
#'
#' * a bullet
#' * another
#'
#' [Links](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) work;
#' so does *emphasis*.
#'
#' To see more of what's possible, check out [commonmark.org/help](https://commonmark.org/help).
#' ")
#' )
markdown <- function(mds, extensions = TRUE, .noWS = NULL, ...) {
html <- rlang::exec(commonmark::markdown_html, glue::trim(mds), extensions = extensions, ...)
htmltools::HTML(html, .noWS = .noWS)
}

View File

@@ -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", "3.4.1", 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")

142
R/test-server.R Normal file
View File

@@ -0,0 +1,142 @@
# Constructs an rlang::eval_tidy() data mask with semantics appropriate for use
# in testServer().
#
# env is assumed to be session$env, or the environment captured by invoking a
# module under test.
#
# Consider the following module definition and its enclosing environment:
#
# x <- 1
# m <- function(id) {
# y <- 2
# moduleServer(id, function(input, output, session){
# z <- 3
# })
# }
#
# The data mask returned by this function should include z, session,
# output, input, y, and id, but *not* x. Definitions not masked are
# resolved in the environment in which testServer() is called.
#
# env is cloned because rlang::new_data_mask() mutates the parent of its `top`
# argument.
#' @importFrom rlang env_clone
buildMask <- function(env) {
if (identical(parent.env(env), emptyenv()))
stop("env must have a non-empty parent")
clone <- env_clone(env, env_clone(parent.env(env), emptyenv()))
rlang::new_data_mask(clone, parent.env(clone))
}
#' @noRd
isModuleServer <- function(x) {
is.function(x) && names(formals(x))[1] == "id"
}
#' Reactive testing for Shiny server functions and modules
#'
#' A way to test the reactive interactions in Shiny applications. Reactive
#' interactions are defined in the server function of applications and in
#' modules.
#' @param app The path to an application or module to test. In addition to
#' paths, applications may be represented by any object suitable for coercion
#' to an `appObj` by `as.shiny.appobj`. Application server functions must
#' include a `session` argument in order to be tested.
#' @param expr Test code containing expectations. The test expression will run
#' in the server function environment, meaning that the parameters of the
#' server function (e.g. `input`, `output`, and `session`) will be available
#' along with any other values created inside of the server function.
#' @param ... Additional arguments to pass to the module function. These
#' arguments are processed with [rlang::list2()] and so are
#' _[dynamic][rlang::dyn-dots]_. If `app` is a module, and no `id` argument is
#' provided, one will be generated and supplied automatically.
#' @return The result of evaluating `expr`.
#' @include mock-session.R
#' @rdname testServer
#' @examples
#' server <- function(id, multiplier = 2, prefix = "I am ") {
#' moduleServer(id, function(input, output, session) {
#' myreactive <- reactive({
#' input$x * multiplier
#' })
#' output$txt <- renderText({
#' paste0(prefix, myreactive())
#' })
#' })
#' }
#'
#' testServer(server, {
#' 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)
#' @export
testServer <- function(app, expr, ...) {
args <- rlang::list2(...)
session <- getDefaultReactiveDomain()
if (inherits(session, "MockShinySession"))
stop("Test expressions may not call testServer()")
if (inherits(session, "session_proxy")
&& inherits(get("parent", envir = session), "MockShinySession"))
stop("Modules may not call testServer()")
session <- MockShinySession$new()
on.exit(if (!session$isClosed()) session$close())
if (isModuleServer(app)) {
if (!("id" %in% names(args)))
args[["id"]] <- session$genId()
} else {
appobj <- as.shiny.appobj(app)
server <- appobj$serverFuncSource()
if (! "session" %in% names(formals(server)))
stop("Tested application server functions must declare input, output, and session arguments.")
appEnv <- new.env(parent = rlang::caller_env())
if (is.character(app)) {
loadSupport(app, appEnv, appEnv)
environment(server) <- appEnv
}
body(server) <- rlang::expr({
session$setEnv(base::environment())
!!!body(server)
})
app <- function() {
session$setReturned(server(input = session$input, output = session$output, session = session))
}
if (length(args))
message("Discarding unused arguments to server function")
}
isolate(
withReactiveDomain(
session,
withr::with_options(list(`shiny.allowoutputreads` = TRUE), {
rlang::exec(app, !!!args)
})
)
)
stopifnot(all(c("input", "output", "session") %in% ls(session$env)))
quosure <- rlang::enquo(expr)
isolate(
withReactiveDomain(
session,
withr::with_options(list(`shiny.allowoutputreads` = TRUE), {
rlang::eval_tidy(quosure, buildMask(session$env), rlang::caller_env())
})
)
)
}

141
R/test.R Normal file
View File

@@ -0,0 +1,141 @@
#' Creates and returns run result data frame.
#'
#' @param file Name of the test runner file, a character vector of length 1.
#' @param pass Whether or not the test passed, a logical vector of length 1.
#' @param result Value (wrapped in a list) obtained by evaluating `file` or `NA`
#' if no value was obtained, such as with `shinytest`.
#' @param error Error, if any, (and wrapped in a list) that was signaled during
#' evaluation of `file`.
#'
#' @return A 1-row data frame representing a single test run. `result` and
#' `error` are "list columns", or columns that may contain list elements.
#' @noRd
result_row <- function(file, pass, result, error) {
stopifnot(is.list(result))
stopifnot(is.list(error))
df <- data.frame(
file = file,
pass = pass,
result = I(result),
error = I(error),
stringsAsFactors = FALSE
)
class(df) <- c("shinytestrun", class(df))
df
}
#' 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.
#'
#' @return A data frame classed with the supplemental class `"shinytestrun"`.
#' The data frame has the following columns:
#'
#' | **Name** | **Type** | **Meaning** |
#' | :-- | :-- | :-- |
#' | `file` | `character(1)` | File name of the runner script in `tests/` that was sourced. |
#' | `pass` | `logical(1)` | Whether or not the runner script signaled an error when sourced. |
#' | `result` | any or `NA` | The return value of the runner, or `NA` if `pass == FALSE`. |
#' | `error` | any or `NA` | The error signaled by the runner, or `NA` if `pass == TRUE`. |
#'
#' @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(result_row(character(0), logical(0), list(), list()))
}
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))
# See the @details section of the runTests() docs above for why this branch exists.
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")
}
return(do.call(rbind, lapply(shinytest::testApp(appDir)[["results"]], function(r) {
error <- if (r[["pass"]]) NA else simpleError("Unknown shinytest error")
result_row(r[["name"]], r[["pass"]], list(NA), list(error))
})))
}
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.
return(do.call(rbind, lapply(runners, function(r) {
result <- NA
error <- NA
pass <- FALSE
tryCatch({
env <- new.env(parent = renv)
result <- sourceUTF8(r, envir = env)
pass <- TRUE
}, error = function(e) {
error <<- e
})
result_row(r, pass, list(result), list(error))
})))
}

View File

@@ -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()
}
}

View File

@@ -316,6 +316,15 @@ resolve <- function(dir, relpath) {
return(abs.path)
}
# Given a string, make sure it has a trailing slash.
ensure_trailing_slash <- function(path) {
if (!grepl("/$", path)) {
path <- paste0(path, "/")
}
path
}
isWindows <- function() .Platform$OS.type == 'windows'
# This is a wrapper for download.file and has the same interface.
@@ -800,7 +809,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])
@@ -1805,3 +1821,20 @@ cat_line <- function(...) {
cat(paste(..., "\n", collapse = ""))
}
select_menu <- function(choices, title = NULL, msg = "Enter one or more numbers (with spaces), or an empty line to exit: \n")
{
if (!is.null(title)) {
cat(title, "\n", sep = "")
}
nc <- length(choices)
op <- paste0(format(seq_len(nc)), ": ", choices)
fop <- format(op)
cat("", fop, "", sep = "\n")
repeat {
answer <- readline(msg)
answer <- strsplit(answer, "[ ,]+")[[1]]
if (all(answer %in% seq_along(choices))) {
return(choices[as.integer(answer)])
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,23 @@
mymoduleUI <- function(id, label = "Counter") {
ns <- NS(id)
tagList(
actionButton(ns("button"), label = label),
verbatimTextOutput(ns("out"))
)
}
mymoduleServer <- function(id) {
moduleServer(
id,
function(input, output, session) {
count <- reactiveVal(0)
observeEvent(input$button, {
count(count() + 1)
})
output$out <- renderText({
count()
})
count
}
)
}

View File

@@ -0,0 +1,5 @@
# Given a numeric vector, convert to strings, sort, and convert back to
# numeric.
lexical_sort <- function(x) {
as.numeric(sort(as.character(x)))
}

View File

@@ -0,0 +1,30 @@
ui <- fluidPage(
# ======== Modules ========
# mymoduleUI is defined in R/my-module.R
mymoduleUI("mymodule1", "Click counter #1"),
mymoduleUI("mymodule2", "Click counter #2"),
# =========================
wellPanel(
sliderInput("size", "Data size", min = 5, max = 20, value = 10),
div("Lexically sorted sequence:"),
verbatimTextOutput("sequence")
)
)
server <- function(input, output, session) {
# ======== Modules ========
# mymoduleServer is defined in R/my-module.R
mymoduleServer("mymodule1")
mymoduleServer("mymodule2")
# =========================
data <- reactive({
# lexical_sort from R/utils.R
lexical_sort(seq_len(input$size))
})
output$sequence <- renderText({
paste(data(), collapse = " ")
})
}
shinyApp(ui, server)

View File

@@ -0,0 +1,6 @@
files <- list.files("./server", full.names = FALSE)
origwd <- getwd()
setwd("./server")
on.exit(setwd(origwd), add=TRUE)
lapply(files, source, local=environment())

View File

@@ -0,0 +1,18 @@
# Use testthat just for expectations
library(testthat)
testServer(mymoduleServer, {
# Set initial value of a button
session$setInputs(button = 0)
# Check the value of the reactiveVal `count()`
expect_equal(count(), 1)
# Check the value of the renderText()
expect_equal(output$out, "1")
# Simulate a click
session$setInputs(button = 1)
expect_equal(count(), 2)
expect_equal(output$out, "2")
})

View File

@@ -0,0 +1,11 @@
# Use testthat just for expectations
library(testthat)
testServer('../..', {
# Set the `size` slider and check the output
session$setInputs(size = 6)
expect_equal(output$sequence, "1 2 3 4 5 6")
session$setInputs(size = 12)
expect_equal(output$sequence, "1 2 3 4 5 6 7 8 9 10 11 12")
})

View File

@@ -0,0 +1,3 @@
library(shinytest)
shinytest::testApp("../")

View File

@@ -0,0 +1,7 @@
app <- ShinyDriver$new("../../")
app$snapshotInit("mytest")
app$snapshot()
app$setInputs(`mymodule1-button` = "click")
app$setInputs(`mymodule1-button` = "click")
app$snapshot()

View File

@@ -0,0 +1,6 @@
library(testthat)
# Run in the "current" environment, because shiny::runTests() is going to
# provision a new environment that's just for our test. And we'll want access to
# the supporting files that were already loaded into that env.
testthat::test_dir("./testthat", env = environment())

View File

@@ -0,0 +1,11 @@
# The RStudio IDE offers a "Run Tests" button when it sees testthat tests but it runs
# in its own environment/process. Which means that any helpers we've loaded into our
# environment won't be visible. So we add this helper not because it's actually needed
# in the typical `shiny::runTests` workflow, but to make that IDE button work.
# Once the IDE adds proper support for this style, we'll be able to drop these files.
#
# Note that this may redundantly source the files in your R/ dir depending on your
# workflow.
library(shiny)
shiny::loadSupport("../../", renv = globalenv())

View File

@@ -0,0 +1,5 @@
# Test the lexical_sort function from R/utils.R
test_that("Lexical sorting works", {
expect_equal(lexical_sort(c(1, 2, 3)), c(1, 2, 3))
expect_equal(lexical_sort(c(1, 2, 3, 13, 11, 21)), c(1, 11, 13, 2, 21, 3))
})

View File

@@ -1,234 +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",
"helpText",
"icon",
"navbarPage",
"navlistPanel",
"sidebarLayout",
"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",
"loadSupport"
)
)
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",
"resourcePaths",
"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",
"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"
)
)

View File

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View 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

File diff suppressed because it is too large Load Diff

5
inst/www/shared/legacy/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -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]);
@@ -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");

View File

@@ -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;
}

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

View File

@@ -1,24 +0,0 @@
\name{HTML}
\alias{HTML}
\title{Mark Characters as HTML}
\usage{
HTML(text, ...)
}
\arguments{
\item{text}{The text value to mark with HTML}
\item{...}{Any additional values to be converted to character and
concatenated together}
}
\value{
The same value, but marked as HTML.
}
\description{
Marks the given text as HTML, which means the \link{tag} functions will know
not to perform HTML escaping on it.
}
\examples{
el <- div(HTML("I like <u>turtles</u>"))
cat(as.character(el))
}

752
man/MockShinySession.Rd Normal file
View File

@@ -0,0 +1,752 @@
% 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{returned}}{The value returned by the module.}
\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{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-setEnv}{\code{MockShinySession$setEnv()}}
\item \href{#method-setReturned}{\code{MockShinySession$setReturned()}}
\item \href{#method-getReturned}{\code{MockShinySession$getReturned()}}
\item \href{#method-genId}{\code{MockShinySession$genId()}}
\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 this namespace's id.
\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-setEnv"></a>}}
\if{latex}{\out{\hypertarget{method-setEnv}{}}}
\subsection{Method \code{setEnv()}}{
Set the environment associated with a testServer() call, but
only if it has not previously been set. This ensures that only the
environment of the outermost module under test is the one retained. In
other words, the first assignment wins.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$setEnv(env)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{env}}{The environment to retain.}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-setReturned"></a>}}
\if{latex}{\out{\hypertarget{method-setReturned}{}}}
\subsection{Method \code{setReturned()}}{
Set the value returned by the module call and proactively
flush. Note that this method may be called multiple times if modules
are nested. The last assignment, corresponding to an invocation of
setReturned() in the outermost module, wins.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$setReturned(value)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{value}}{The value returned from the module}
}
\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-getReturned"></a>}}
\if{latex}{\out{\hypertarget{method-getReturned}{}}}
\subsection{Method \code{getReturned()}}{
Get the value returned by the module call.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$getReturned()}\if{html}{\out{</div>}}
}
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-genId"></a>}}
\if{latex}{\out{\hypertarget{method-genId}{}}}
\subsection{Method \code{genId()}}{
Return a distinct character identifier for use as a proxy
namespace.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{MockShinySession$genId()}\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>}}
}
}
}

View File

@@ -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)

View File

@@ -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>}}
}
}
}

View File

@@ -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

View File

@@ -26,13 +26,24 @@ 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()) {
ui <- fluidPage(
sliderInput("obs", "Number of observations", 0, 1000, 500),
actionButton("goButton", "Go!"),
actionButton("goButton", "Go!", class = "btn-success"),
plotOutput("distPlot")
)
@@ -52,17 +63,28 @@ shinyApp(ui, server)
}
## Example of adding extra class values
actionButton("largeButton", "Large Primary Button", class = "btn-primary btn-lg")
actionLink("infoLink", "Information Link", class = "btn-info")
}
\seealso{
\code{\link[=observeEvent]{observeEvent()}} and \code{\link[=eventReactive]{eventReactive()}}
Other input elements: \code{\link{checkboxGroupInput}},
\code{\link{checkboxInput}}, \code{\link{dateInput}},
\code{\link{dateRangeInput}}, \code{\link{fileInput}},
\code{\link{numericInput}}, \code{\link{passwordInput}},
\code{\link{radioButtons}}, \code{\link{selectInput}},
\code{\link{sliderInput}}, \code{\link{submitButton}},
\code{\link{textAreaInput}}, \code{\link{textInput}},
\code{\link{varSelectInput}}
Other input elements:
\code{\link{checkboxGroupInput}()},
\code{\link{checkboxInput}()},
\code{\link{dateInput}()},
\code{\link{dateRangeInput}()},
\code{\link{fileInput}()},
\code{\link{numericInput}()},
\code{\link{passwordInput}()},
\code{\link{radioButtons}()},
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}
}
\concept{input elements}

View File

@@ -4,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

View File

@@ -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"},

View File

@@ -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.}

View File

@@ -1,124 +0,0 @@
\name{builder}
\alias{builder}
\alias{tags}
\alias{p}
\alias{h1}
\alias{h2}
\alias{h3}
\alias{h4}
\alias{h5}
\alias{h6}
\alias{a}
\alias{br}
\alias{div}
\alias{span}
\alias{pre}
\alias{code}
\alias{img}
\alias{strong}
\alias{em}
\alias{hr}
\title{HTML Builder Functions}
\usage{
tags
p(..., .noWS = NULL)
h1(..., .noWS = NULL)
h2(..., .noWS = NULL)
h3(..., .noWS = NULL)
h4(..., .noWS = NULL)
h5(..., .noWS = NULL)
h6(..., .noWS = NULL)
a(..., .noWS = NULL)
br(..., .noWS = NULL)
div(..., .noWS = NULL)
span(..., .noWS = NULL)
pre(..., .noWS = NULL)
code(..., .noWS = NULL)
img(..., .noWS = NULL)
strong(..., .noWS = NULL)
em(..., .noWS = NULL)
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), 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.
}
\details{
The \code{tags} environment contains convenience functions for all valid
HTML5 tags. To generate tags that are not part of the HTML5 specification,
you can use the \code{\link{tag}()} function.
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{as.character}()}.
}
\examples{
doc <- tags$html(
tags$head(
tags$title('My first page')
),
tags$body(
h1('My first heading'),
p('My first paragraph, with some ',
strong('bold'),
' text.'),
div(id='myDiv', class='simpleDiv',
'Here is a div with some attributes.')
)
)
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}
}
}

View File

@@ -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}
}

View File

@@ -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}

View File

@@ -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}

View File

@@ -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

View File

@@ -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}

View File

@@ -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}

View File

@@ -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}{

View File

@@ -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

View File

@@ -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

View File

@@ -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())
})
}
)

View File

@@ -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}

View File

@@ -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}

View File

@@ -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}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,29 +0,0 @@
\name{htmlTemplate}
\alias{htmlTemplate}
\title{Process an HTML template}
\usage{
htmlTemplate(filename = NULL, ..., text_ = NULL, document_ = "auto")
}
\arguments{
\item{filename}{Path to an HTML template file. Incompatible with
\code{text_}.}
\item{...}{Variable values to use when processing the template.}
\item{text_}{A string to use as the template, instead of a file. Incompatible
with \code{filename}.}
\item{document_}{Is this template a complete HTML document (\code{TRUE}), or
a fragment of HTML that is to be inserted into an HTML document
(\code{FALSE})? With \code{"auto"} (the default), auto-detect by searching
for the string \code{"<HTML>"} within the template.}
}
\description{
Process an HTML template and return a tagList object. If the template is a
complete HTML document, then the returned object will also have class
\code{html_document}, and can be passed to the function
\code{\link{renderDocument}} to get the final HTML text.
}
\seealso{
\code{\link{renderDocument}}
}

View File

@@ -1,44 +0,0 @@
\name{include}
\alias{include}
\alias{includeHTML}
\alias{includeText}
\alias{includeMarkdown}
\alias{includeCSS}
\alias{includeScript}
\title{Include Content From a File}
\usage{
includeHTML(path)
includeText(path)
includeMarkdown(path)
includeCSS(path, ...)
includeScript(path, ...)
}
\arguments{
\item{path}{The path of the file to be included. It is highly recommended to
use a relative path (the base path being the Shiny application directory),
not an absolute path.}
\item{...}{Any additional attributes to be applied to the generated tag.}
}
\description{
Load HTML, text, or rendered Markdown from a file and turn into HTML.
}
\details{
These functions provide a convenient way to include an extensive amount of
HTML, textual, Markdown, CSS, or JavaScript content, rather than using a
large literal R string.
}
\note{
\code{includeText} escapes its contents, but does no other processing.
This means that hard breaks and multiple spaces will be rendered as they
usually are in HTML: as a single space character. If you are looking for
preformatted text, wrap the call with \code{\link{pre}}, or consider using
\code{includeMarkdown} instead.
The \code{includeMarkdown} function requires the \code{markdown}
package.
}

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