Compare commits

...

1748 Commits

Author SHA1 Message Date
Winston Chang
46da93519f Bump version to 0.13.0 2016-01-12 13:33:14 -06:00
Winston Chang
ce0f2c51a9 Use explicit namespaces 2016-01-12 13:33:14 -06:00
Winston Chang
04b4b8da4f Use --run-donttest when checking package 2016-01-12 13:16:18 -06:00
Winston Chang
877d7451dd Merge pull request #1073 from rstudio/joe/staticdocs-tweaks
Tweaks for improved staticdocs rendering
2016-01-12 13:00:07 -06:00
Joe Cheng
7e6a68a2b1 CRAN maintainers prefer \donttest over \dontrun 2016-01-12 10:10:16 -08:00
Joe Cheng
caca515ba0 Tweaks for improved staticdocs rendering
- \donttest -> \dontrun, otherwise staticdocs hangs
- Put NS before ns.sep so usage entries are in a better order
2016-01-11 12:20:19 -08:00
Joe Cheng
f2410abc48 Merge remote-tracking branch 'origin/image-attr'
Conflicts:
	inst/www/shared/shiny.js
	inst/www/shared/shiny.js.map
	inst/www/shared/shiny.min.js
	inst/www/shared/shiny.min.js.map
2016-01-08 10:55:21 -08:00
Joe Cheng
483a7d34c5 Merge pull request #1071 from rstudio/fix-hidden-slider
Fix hidden slider
2016-01-08 10:53:00 -08:00
Winston Chang
e872411285 Build and minify shiny.js 2016-01-08 10:00:22 -06:00
Winston Chang
fc7e6bf542 Revert "Simpler fix for updating hidden sliders (#1010)"
This reverts commit 4e1caee7da.
See https://github.com/rstudio/shiny/issues/1010#issuecomment-169971201
2016-01-08 10:00:05 -06:00
Winston Chang
16d42b6421 Add bootstrapLib to staticdocs index 2016-01-07 13:51:56 -06:00
Winston Chang
2f25d25eec Use setAttribute() function to set image attributes. Fixes #936 2016-01-06 15:03:18 -06:00
Winston Chang
be1081a4b9 Add note about printing ggplot2 graphics 2016-01-06 14:11:16 -06:00
Joe Cheng
1608b652d7 Fix unnecessary ::: 2016-01-05 14:02:16 -08:00
Winston Chang
5dd19a878c Bump version to 0.2.12.9009 2016-01-05 15:59:19 -06:00
Winston Chang
3314f4b5b8 Update NEWS 2016-01-05 15:59:11 -06:00
Winston Chang
5977e0fe89 Update NEWS 2016-01-05 15:30:59 -06:00
Winston Chang
f477dcba4a Merge pull request #1068 from rstudio/template-bootstrap
Pull out bootstrapLib into separate function
2016-01-05 15:30:32 -06:00
Winston Chang
6c5f0c5379 Pull out bootstrapLib into separate function 2016-01-05 14:57:53 -06:00
Winston Chang
257eb1bed0 Merge pull request #1067 from rstudio/joe/bugfix/module-progress
Fix progress for Shiny modules
2016-01-05 11:59:18 -06:00
Joe Cheng
9c4d142c2d Fix progress for Shiny modules
Too-specific class check was being used, interfered with the
"duck typed" session-like objects we use for modules.
2016-01-05 09:41:52 -08:00
Winston Chang
8e89a1f154 Add README file with info about jQuery UI 2016-01-05 11:03:34 -06:00
Winston Chang
b0952c0374 Use jQuery UI build without datepicker. Fixes #1042 2016-01-05 11:03:07 -06:00
Winston Chang
ac95dcb3f2 Fix head content location 2016-01-04 10:52:26 -06:00
Joe Cheng
ce4043f038 Update metadata 2015-12-31 11:07:35 -08:00
Joe Cheng
0d26857e31 Merge pull request #1031 from rstudio/template
Use templates from htmltools
2015-12-31 11:03:14 -08:00
Joe Cheng
85bea95f6b Merge pull request #1029 from rstudio/joe/feature/knit_print.reactive
Add knit_print.reactive
2015-12-30 14:31:26 -08:00
Winston Chang
10a46c507f Merge pull request #1059 from rstudio/joe/bugfix/gadgets
Fix stopApp bug, and fix flex box in RStudio
2015-12-30 09:38:24 -06:00
Joe Cheng
d35d76e1d0 Use flex box layout vendor prefixes
This fixes fillRow/fillCol for RStudio on Windows and Linux
2015-12-29 15:59:04 -08:00
Joe Cheng
aaa05b22df Return stopApp value without visibility info 2015-12-29 15:57:23 -08:00
Winston Chang
c5fa30f0de Make encoding tests work cleanly on different platforms 2015-12-29 15:41:49 -06:00
Joe Cheng
43fe1a9a0e Merge pull request #1057 from rstudio/joe/feature/gadget-cancel
runGadget automatically handles cancel button
2015-12-28 14:18:17 -08:00
Joe Cheng
aa296fcb69 Don't show call when user cancels gadget 2015-12-28 13:56:01 -08:00
Joe Cheng
b9c7023489 Refactor server function arg matching 2015-12-28 12:43:06 -08:00
Joe Cheng
efcd286039 Code review feedback 2015-12-28 11:56:13 -08:00
Joe Cheng
98014f9495 Code review feedback 2015-12-28 11:53:52 -08:00
Joe Cheng
2702a18ea2 Add stopApp test 2015-12-28 11:18:15 -08:00
Joe Cheng
4a8da3e1e2 runGadget handles cancel automatically (by default) 2015-12-27 23:46:47 -08:00
Joe Cheng
cfe38c00f3 Proper visibility and error handling from stopApp 2015-12-27 23:35:09 -08:00
Joe Cheng
af0463ed46 Update metadata 2015-12-23 17:47:24 -08:00
Joe Cheng
c02f4691e0 Merge pull request #1054 from rstudio/joe/feature/runGadget
Migrate runGadget and viewer functions from shinygadgets
2015-12-23 17:45:12 -08:00
Joe Cheng
5d89393fff Merge pull request #1039 from rstudio/joe/feature/fillPage
Add fillPage, flexRow, flexCol
2015-12-23 17:44:56 -08:00
Joe Cheng
e7ce28204b Remove dependency on newer htmltools
The css function is in htmltools 0.2.11, which isn't on CRAN
yet. Due to a perfect storm of release scheduling we need to
get fillPage onto shiny master before we have a chance to
put htmltools on CRAN.
2015-12-23 17:32:46 -08:00
Joe Cheng
8fc4a75e8c Specify remote repo for htmltools
Makes devtools install easier
2015-12-23 17:31:11 -08:00
Joe Cheng
26c89a09e8 Update staticdocs index 2015-12-23 17:31:11 -08:00
Joe Cheng
25a1493520 Add details to fillRow doc about containers 2015-12-23 17:31:10 -08:00
Joe Cheng
b18722f776 flex:none is more appropriate than flex:initial for weight=NA 2015-12-23 17:31:10 -08:00
Joe Cheng
3f3fd9ae21 Install htmltools from github until 0.2.11 goes to cran 2015-12-23 17:31:10 -08:00
Joe Cheng
94ea3c7dab Require htmltools 0.2.11 2015-12-23 17:31:10 -08:00
Joe Cheng
6c2fea7926 Rename flexRow/flexCol to fillRow/fillCol, other tweaks
I decided against the name flexRow/flexCol as the "flex" prefix
is too general for these implementations, which are mostly just
useful for filling the space with the children. Flex box has a
lot more features than that, such as centering, wrapping,
justifying, etc., but I don't currently know how to design an
API that presents the full power of flex box without also
presenting the full complexity of it as well.

This commit also includes some tweaks to the impl of flexfill
to fix the behavior of children with 100% size along the main
axis, and also introduces support for NA flex values, which
sizes the flex item according to its contents.
2015-12-23 17:31:10 -08:00
Joe Cheng
e08fd47b0e Add fillPage, flexRow, flexCol 2015-12-23 17:31:05 -08:00
Joe Cheng
0fd76e8768 Migrate runGadget and viewer functions from shinygadgets 2015-12-23 15:33:30 -08:00
Joe Cheng
72aaf3055a Update NEWS 2015-12-23 11:46:03 -08:00
Winston Chang
94a943a68c Merge pull request #1052 from rstudio/joe/font-awesome-4.5.0
Upgrade Font Awesome to 4.5.0
2015-12-23 13:08:27 -06:00
Joe Cheng
e867dcfdb1 Upgrade Font Awesome to 4.5.0 2015-12-23 11:03:33 -08:00
Joe Cheng
9a22a89b06 Add docs 2015-12-23 09:42:29 -08:00
Joe Cheng
791e8200bc Install htmltools from github until 0.2.11 goes to cran 2015-12-22 14:06:51 -08:00
Joe Cheng
d96217d49a Merge pull request #1049 from rstudio/joe/bugfix/http-iframe-stampede
Defer subapp iframe loading
2015-12-22 12:26:49 -08:00
Joe Cheng
6bfd65aa19 Guard against window.Shiny not being defined 2015-12-22 11:53:36 -08:00
Joe Cheng
2da9bc07ac Defer subapp iframe loading until main app has loaded
Fixes #1047 defer loading of iframes
2015-12-22 11:14:12 -08:00
Joe Cheng
6d7a562b7a Fix staticdocs
Without this fix, current version of staticdocs won't pull plotOutput
into the index page.
2015-12-21 11:57:01 -08:00
Joe Cheng
0aa1dfb8e1 Merge pull request #1032 from yihui/yihui/encoding-tests
Add some tests for character encodings
2015-12-17 13:36:26 -08:00
Winston Chang
e9e7dc298f Merge pull request #1037 from rstudio/joe/feature/req
Add `req` function for validating required inputs/values
2015-12-17 14:39:40 -06:00
Joe Cheng
ed3b71e396 Remove unnecessary environment() call 2015-12-17 11:58:17 -08:00
Joe Cheng
3450a037a9 Further simplification and more tests for req() 2015-12-17 11:29:54 -08:00
Joe Cheng
f57626d256 req() simplification 2015-12-17 11:16:09 -08:00
Joe Cheng
c1c3fa4d3a Fix a couple of req edge cases 2015-12-17 11:13:33 -08:00
Joe Cheng
300433f7de req() now short-circuits on falsy values 2015-12-17 10:53:13 -08:00
Joe Cheng
eee6f4ed81 Add req function for validating required inputs/values 2015-12-16 10:04:05 -08:00
Joe Cheng
2eb29bd8aa Merge pull request #1034 from rstudio/fix-hidden-slider
Simpler fix for updating hidden sliders (#1010)
2015-12-15 15:57:11 -08:00
Joe Cheng
3a0ce86f51 Remove unnecessary check (feedback from @wch) 2015-12-15 15:36:43 -08:00
Joe Cheng
6041b8cbb2 Roxygenize 2015-12-14 18:00:29 -08:00
Joe Cheng
3ba8fcb7b8 Merge pull request #1036 from rstudio/joe/bugfix/validation-error-behavior
Fix validation error handling
2015-12-14 17:16:04 -08:00
Joe Cheng
f74d9c93a2 Merge pull request #1035 from rstudio/joe/bugfix/multiline-label
Fix warnings when renderXXX is called with explicit namespace
2015-12-14 17:15:50 -08:00
Joe Cheng
739c162281 Fix warnings when renderXXX is called with explicit namespace
Calling shiny::renderText(...) instead of renderText(...) would
cause warnings.
2015-12-14 17:11:40 -08:00
Joe Cheng
a2700c900d Fix validation error handling
Validation errors were behaving too much like real errors: they were
being printed with stack traces, and passed to the options(shiny.error)
function. Also, if a reactive() cached a validation error, on future
calls the error would be re-raised (which is correct) without the
custom class names attached (which is not).
2015-12-14 16:31:57 -08:00
Winston Chang
4e1caee7da Simpler fix for updating hidden sliders (#1010)
This also reverts the previous fix, #1026
2015-12-10 15:49:23 -06:00
Yihui Xie
76a54249bb Add some tests for character encodings 2015-12-10 15:23:31 -06:00
Winston Chang
0e894cb043 Use templates from htmltools 2015-12-10 15:11:03 -06:00
Winston Chang
01bbee59eb Merge pull request #1023 from yihui/bugfix/1018
Fixes #1018: make sure the selected value is always returned from sever-side selectize
2015-12-10 13:44:24 -06:00
Joe Cheng
26a0c3520c Add knit_print.reactive
Allows us to drop reactive expressions right into Rmd docs
with runtime:shiny and have them stay up-to-date.
2015-12-09 16:34:55 -08:00
Yihui Xie
6056c35de3 add a news item, and run grunt 2015-12-09 11:56:13 -06:00
Yihui Xie
4202991ca5 Fixes #1018: make sure the selected value is always returned from server-side selectize 2015-12-09 11:52:50 -06:00
Joe Cheng
788931c7c7 Merge pull request #1027 from yihui/yihui/srcfilecopy
Check R version at runtime (#968)
2015-12-09 09:48:59 -08:00
Yihui Xie
b2d0505c7c Check R version at runtime (#968) 2015-12-08 20:33:52 -06:00
Winston Chang
8b710d651f Merge pull request #1026 from rstudio/joe/bugfix/hidden-slider-update
Fix #1010: updateSliderInput doesn't update hidden sliders
2015-12-08 19:50:12 -06:00
Joe Cheng
93697bb01d Merge pull request #1025 from yihui/bugfix/source-utf8
Fixes #1003: correctly parse source code that can be represented with native encoding
2015-12-08 15:51:51 -08:00
Joe Cheng
89cd58e4f8 Fix #1010: updateSliderInput doesn't update hidden sliders 2015-12-08 11:13:18 -08:00
Yihui Xie
a622f029a0 Fixes #1003: when the source code can be represented via the native encoding on Windows, rewrite the code to a temporary file with the native encoding and parse it 2015-12-07 16:28:45 -06:00
Winston Chang
97afb52904 Re-document with Roxygen2 5.0.1 2015-12-02 15:43:25 -06:00
Joe Cheng
02ea31be08 Fix #1020: Graphics are cut off 2015-12-01 13:47:26 -08:00
Joe Cheng
b5e49a6619 Fix bugs reported by @daattali
- reactive srcrefToLabel call fails if code is pasted in at RStudio console
- Stack trace fails when promise (!?) is in call stack
2015-11-24 11:55:08 -08:00
Joe Cheng
179c931f85 Bump version 2015-11-23 10:58:30 -08:00
Joe Cheng
4d3fa2c8ac Merge pull request #1011 from rstudio/joe/feature/better-errors
Better errors
2015-11-20 12:56:24 -08:00
Joe Cheng
8e4f7387d0 Better stack traces for observeEvent and eventReactive 2015-11-16 13:10:53 -08:00
Joe Cheng
feb630b2c5 Catch errors when trying to print stack trace
No known errors will occur when printing the stack trace, but since
this is fairly complicated code executing when an error has already
happened, better to be on the defensive.
2015-11-16 13:08:34 -08:00
Joe Cheng
948dfbb56b More tests 2015-11-16 12:50:20 -08:00
Joe Cheng
5c3ac75b34 Errors in ui function should get stack traces 2015-11-16 12:46:22 -08:00
Joe Cheng
adc5c8e37a Normalize shiny dir in smoketest stack traces 2015-11-16 12:45:59 -08:00
Joe Cheng
52d594c143 Quick and dirty smoke test infrastructure 2015-11-16 12:29:02 -08:00
Joe Cheng
1018b0d966 Errors in ui.R, server.R, server func, etc. all get stack traces 2015-11-16 10:48:16 -08:00
Joe Cheng
0ce153d788 Doc updates
Code had to be rearranged to make the functions show up in the
help docs in the right order
2015-11-14 00:26:23 -08:00
Joe Cheng
ff9756c739 Add more exports, tests 2015-11-14 00:17:19 -08:00
Joe Cheng
b3dd7e5397 Remove support for shiny.observer.error option
It is dangerous to set this on a per-process basis. If we even
still want the ability to have observer errors not kill the
session (debatable) we should do so by having an option on the
session object that is set when the shiny server function runs.

Not only does this remove support for the option, but now we
will refuse to connect and will abort the session if the option
is set to a non-NULL value. This is to prevent apps from moving
forward with the assumption that their option will work, when
it really won't. (I doubt anyone is using it anyway, it's so
obscure...)
2015-11-13 18:13:14 -08:00
Joe Cheng
6ac0a80896 Update NEWS with stack trace announcement 2015-11-13 17:58:18 -08:00
Joe Cheng
93f774c7e7 Add exports/docs 2015-11-13 17:52:26 -08:00
Joe Cheng
661c08549d Automatically wrap installExprFunction with function labels
This lowers the burden on renderXXX functions having nice stack traces
2015-11-13 16:43:15 -08:00
Joe Cheng
c8acc44012 Add comments to stacktraceon/off directives indicating their partners 2015-11-13 16:25:22 -08:00
Joe Cheng
aabf00659e Random improvements to stack traces
- More selective removal of frames at end of call stack
- Add withLogErrors, printError, stripStackTrace convenience funcs
- Properly capture/log errors for various levels of unhandled errors
- Unhide stacks for flush/flushed/sessionended callbacks
2015-11-13 16:03:18 -08:00
Joe Cheng
a9bc41492c Collapse stack trace to eliminate irrelevant bits 2015-11-13 12:36:55 -08:00
Winston Chang
12b0484e9a Merge pull request #875 from wch/rendertable-args
Separate xtable from print.xtable args. Closes #761
2015-11-13 11:48:41 -06:00
Joe Cheng
d3605dbcb3 Collapse parts of the stack 2015-11-12 16:40:56 -08:00
Joe Cheng
d9a016f94c Move error-handling logic into conditions.R 2015-11-11 16:20:26 -08:00
Joe Cheng
a13657ac23 Work properly with non-call sys.call() objects 2015-11-11 15:54:03 -08:00
Joe Cheng
d6c95a9e89 wip 2015-11-11 12:14:42 -08:00
Winston Chang
825e9e04c1 Get xtable args using formals() 2015-11-05 13:04:43 -06:00
Winston Chang
c596e44c5a Separate xtable from print.xtable args. Closes #761 2015-11-05 13:01:01 -06:00
Winston Chang
66be9004fe Move renderTable to separate file 2015-11-05 12:59:04 -06:00
Winston Chang
119ebb0f07 Merge pull request #1005 from rstudio/joe/bootstrap-3.3.5
Upgrade bootstrap to 3.3.5
2015-11-05 12:43:34 -06:00
Joe Cheng
d509fcac29 Merge pull request #1004 from rstudio/joe/feature/autoreload
Implement autoreload
2015-11-05 10:43:13 -08:00
Joe Cheng
c79e933586 Merge pull request #1002 from rstudio/joe/bugfix/nested-scopes
Fix nested scopes
2015-11-05 10:32:23 -08:00
Joe Cheng
3c3cfc02a0 Merge pull request #997 from wch/download-fix
Update download to work correctly with R 3.2.2 on Mac. Fixes #996
2015-11-05 10:27:51 -08:00
Joe Cheng
e32de7b940 Update bootstrap htmlDependency version 2015-11-05 07:38:00 -08:00
Joe Cheng
d7b1759afb Upgrade bootstrap to 3.3.5 2015-11-04 22:56:31 -08:00
Joe Cheng
e391c1fda3 Implement autoreload 2015-11-04 13:44:38 -08:00
Joe Cheng
46d8d3b469 Fix nested scopes
The session$makeScope function was not correctly taking the session's
own namespace into account (i.e. all makeScope() method calls were
being performed against the root session).
2015-11-03 12:33:39 -08:00
Joe Cheng
9fde7509fa Merge pull request #1000 from rstudio/joe/feature/invalidatelater-default-session
Don't require session to be explicitly passed to invalidateLater
2015-11-02 16:21:43 -08:00
Joe Cheng
a767a61f43 Don't require session to be explicitly passed to invalidateLater
These functions were created before getDefaultReactiveDomain()
existed, so the only way to get ahold of the current session was
if the caller explicitly passed it.

This is slightly backwards incompatible, in that existing calls
to invalidateLater() that don't pass a session argument will
behave slightly differently (bound to the current session instead
of to no session), but those calls would have triggered a warning
for all but the very earliest versions of Shiny.
2015-11-02 14:19:29 -08:00
Joe Cheng
ad28e03536 Merge pull request #999 from yihui/bugfix/ie9-upload
Fixes #990: revert to checking if FileList is supported by the browser
2015-11-02 11:13:57 -08:00
Yihui Xie
5f9e9c2e03 grunt 2015-11-02 12:21:56 -06:00
Yihui Xie
2be6d7a65c Fixes #990: revert to checking if FileList is supported by the browser, instead of checking IE8 literally (partially reverted a41e1dafc2) 2015-11-02 12:21:30 -06:00
Winston Chang
712c4cb985 Update download to work correctly with R 3.2.2 on Mac. Fixes #996 2015-10-30 12:08:48 -05:00
Winston Chang
7948a0a4fa Merge pull request #993 from rstudio/joe/feature/reactlog-labels
Cleaner reactlog labels for reactives and outputs
2015-10-30 11:57:57 -05:00
Joe Cheng
ce9e95f256 Fix parseQueryString example (thanks Chris Beeley) 2015-10-29 16:15:47 -07:00
Joe Cheng
7ed5ca94a2 reactlog label code review feedback
- Don't clobber explicitly-provided label
- Let `reactives$x1 <- reactive(...)` work
2015-10-29 10:27:06 -07:00
Winston Chang
e635589c52 Merge pull request #992 from rstudio/joe/feature/reactlog-time
Add timing data to reactlog entries
2015-10-29 10:06:08 -05:00
Joe Cheng
490721437f Merge pull request #994 from RCura/patch-1
Correct a regression within modules
2015-10-28 18:23:36 -07:00
Robin Cura
7e25a1566f Correct a regression within modules
Commit 07f2792cf9 introduced an error, replacing `e$parent = parentSession` with `e$parent <= parentSession`, while it should have been `e$parent <- parentSession`
2015-10-29 02:03:12 +01:00
Joe Cheng
c08b3b0c30 Update metadata 2015-10-28 15:30:07 -07:00
Joe Cheng
f1de132a2a Merge pull request #988 from rstudio/joe/feature/namespaces
Shiny modules
2015-10-28 15:22:57 -07:00
Joe Cheng
c440c60bdf Cleaner reactlog labels for reactives and outputs
Instead of showing the code, try to just show the name
of the reactive/output. Uses a fairly flaky algorithm
for determining the name of the reactive; will only
work in cases where the definition of the reactive
begins with "foo <- reactive({".
2015-10-28 14:37:00 -07:00
Joe Cheng
c367176a17 Add timing data to reactlog entries 2015-10-28 13:49:39 -07:00
Joe Cheng
3d13c39a4c Also override registerDataObj (essential for data table, DT, and selectize server mode) 2015-10-27 16:33:46 -07:00
Joe Cheng
07f2792cf9 Change evil = to righteous <- 2015-10-27 15:01:44 -07:00
Joe Cheng
303fce5f15 Merge pull request #983 from wch/clear-checkbox
updateCheckboxGroup: allow clearing all choices. Fixes #981
2015-10-27 15:00:20 -07:00
Joe Cheng
46c8bfdd34 Merge pull request #979 from wch/profiling-enhancements
Enhancements to help profiling
2015-10-27 14:59:59 -07:00
Winston Chang
c36a22ad5e Add information about clearing choices 2015-10-23 16:04:17 -05:00
Winston Chang
49eba95a9c Simplify function naming 2015-10-23 15:48:33 -05:00
Winston Chang
2dacc6ce40 Use cleaner method for generating function 2015-10-23 15:44:24 -05:00
Winston Chang
5ccf02f5c3 Merge pull request #984 from rstudio/update-jquery
Update to jQuery 1.11.3 and jQuery UI 1.11.4
2015-10-23 15:08:27 -05:00
Joe Cheng
86c67de8ff Add session$ns(); some light refactoring; add tests; fix staticdocs 2015-10-20 23:49:24 -07:00
Joe Cheng
dac7eb5997 Simplify modules, by removing moduleUI and path arguments 2015-10-20 15:12:11 -07:00
Winston Chang
fd725552a5 Update to jQuery UI 1.11.4 2015-10-19 13:44:23 -05:00
Winston Chang
1e1a897970 Update to jQuery 1.11.3 2015-10-19 13:31:44 -05:00
Joe Cheng
59a643c006 Update metadata 2015-10-16 10:24:05 -07:00
Joe Cheng
1a492208e6 Merge pull request #982 from rstudio/feature/single-file-runapp
Let runApp accept single .R file parameters
2015-10-16 10:16:29 -07:00
Winston Chang
bc0a19f55d updateCheckboxGroup: allow clearing all choices. Fixes #981 2015-10-16 11:44:09 -05:00
Jonathan McPherson
85e2e00bc4 let runApp accept single .R file parameters 2015-10-16 09:22:44 -07:00
Joe Cheng
93dd8bbf28 Merge pull request #980 from rstudio/joe/bugfix/select-value-escaping
Fix improperly escaped quote chars in select choices
2015-10-15 12:56:54 -07:00
Joe Cheng
2f15a219df Fix improperly escaped quote chars in select choices 2015-10-15 12:49:50 -07:00
Yihui Xie
4fc73b1344 A news item for #968 2015-10-15 13:45:00 -05:00
Joe Cheng
48b56ba08d Merge pull request #968 from yihui/bugfix/961-unicode
A more fundamental fix to the Unicode issue
2015-10-15 11:17:45 -07:00
Joe Cheng
94ca733c7c Merge pull request #967 from rstudio/joe/bugfix/placeholder
Add placeholder parameter to textInput
2015-10-15 11:15:10 -07:00
Winston Chang
4af2436a0e Rename 'func' to more descriptive name 2015-10-14 16:40:33 -05:00
Winston Chang
20c2bb9d50 Simplify try(tryCatch()) to just tryCatch()
This also has the benefit of printing a more helpful error message at
the console. It now indicates which output an error occurred in.
2015-10-14 16:40:33 -05:00
Winston Chang
33bac0db3c Add function relabeler and relabel outputs 2015-10-14 16:40:33 -05:00
Winston Chang
8893db9098 Update NEWS 2015-10-12 22:39:51 -05:00
Winston Chang
c46658a5c8 Correctly handle unit and unit.list objects. Closes #962 2015-10-12 22:31:32 -05:00
Joe Cheng
5f651aed3e LICENSE typo 2015-10-12 12:32:00 -04:00
Joe Cheng
534bc9c6e2 Pass tests 2015-10-05 15:15:54 -04:00
Joe Cheng
bb09885237 Add callModule/moduleUI functions; scope sendInputMessage 2015-10-05 14:56:01 -04:00
Joe Cheng
3ff6aaa6db Add namespacing functionality
- Need to carefully review ShinySession, think about
  each and every public method and whether it should
  be passthrough or do something different for a
  namespaced session.

- It would be nice if we do the namespace splitting
  at the server.R level and actually have numerous
  reactivevalues objects for inputs, one for each
  namespace. This will make the reactive hooks for
  names() and reactiveValuesToList() correct, as
  right now they will oversubscribe if you're in a
  namespaced session. Also it would prevent outer
  sessions from seeing the values of their child
  namespaces. (Though is that good or bad...?)
2015-10-02 12:51:18 -07:00
Joe Cheng
fa7c034d16 Merge pull request #955 from rstudio/joe/feature/reactlog-bysession
Fix couple of issues with reactlog
2015-09-24 09:54:35 -07:00
Joe Cheng
ca870ccd75 Merge pull request #966 from rstudio/joe/bugfix/showcase-highlighting
Fix highlighting of reactives in showcase mode
2015-09-24 09:54:01 -07:00
Yihui Xie
89fe2ff217 a more fundamental fix of the Unicode issue
for R <= 3.2.2, Unicode chars don't work for shiny mainly because we want to
preserve the source reference, and unfortunately srcfilecopy() fails because of
the bug https://bugs.r-project.org/bugzilla3/show_bug.cgi?id=16264

here I use lines = '' to get around the bug, and assign the source lines to
the srcfile object later, so there is no grep("\n", multibyte_chars) occuring

I also replaced source() with a custom version, which is much simpler and works
better with Unicode chars
2015-09-23 23:00:20 -05:00
Joe Cheng
6c6775376e Add placeholder parameter to textInput 2015-09-23 18:28:08 -07:00
Yihui Xie
bd3b3881d8 after reading a file as UTF-8, try to convert it to native encoding on Windows only if the conversion is not lossy 2015-09-23 18:33:01 -05:00
Yihui Xie
078189599c the check is.na(iconv(x, 'UTF-8')) does not really make sense
e.g. iconv('\u2264', 'UTF-8') converts the smaller than or equal sign to an
equal sign in the English (US) locale, which is lossy

we just assume the input is UTF-8 instead, and do not fall back to native
encoding any more
2015-09-23 18:31:16 -05:00
Yihui Xie
9afcd2a411 don't declare encoding on the anonymouse file connection
otherwise writeLines(useBytes = TRUE) may not work (#961)
2015-09-22 01:11:38 -05:00
Yihui Xie
0afd1649c1 textConnection() can be lossy; use an anonymous file connection instead to preserve UTF-8 characters 2015-09-22 01:11:37 -05:00
Yihui Xie
0947a63103 make sure writeLines() does not convert text to native encoding 2015-09-22 01:11:32 -05:00
Yihui Xie
79223bddc5 make sure the UI HTML is rendered into a connection with UTF-8 encoding 2015-09-21 22:25:12 -05:00
Yihui Xie
1871dd6b71 convert the result of readLines() to UTF-8 using enc2utf8() instead, since enc2native() can be lossy 2015-09-21 21:49:12 -05:00
Yihui Xie
4adc3088d1 fixes #961: the JSON string from jsonlite::toJSON() is always encoded in UTF-8, so there is no need to re-encode it
actually re-encoding the string with native encoding can be lossy (some UTF-8 characters may not be representable in the native encoding)
2015-09-21 21:46:11 -05:00
Yihui Xie
79dd7e1bf5 shiny requires R >= 3.0.0 2015-09-21 21:44:03 -05:00
Joe Cheng
6718d377bb Fix and enhance reactlog
* Reactlog shortcut was broken due to reactlog.js not being included in
  the gruntfile
* Reactlog has always shown every reactive event since the beginning of
  the process (or at least since options(shiny.reactlog=TRUE)). This
  commit makes it so Ctrl+F3 invocation only shows reactives that either
  belong to no session (e.g. observers and reactives declared at the top
  of server.R), or belong to this session.
2015-09-13 02:46:52 -07:00
Joe Cheng
d4e3329d7a Fix highlighting of reactives in showcase mode
This has been broken since we switched to jsonlite. Reactives
don't highlight because their srcref is in an S3(?) class that
jsonlite doesn't recognize, whereas RJSONIO would treat it as
a numeric vector.
2015-09-12 20:20:13 -07:00
Joe Cheng
99295f0983 Bump version, update NEWS 2015-09-09 22:13:45 -07:00
Winston Chang
3606c36cb9 Merge pull request #950 from rstudio/joe/feature/grunt-clean
Add 'grunt clean' to delete shiny build artifacts
2015-09-09 15:49:02 -05:00
Winston Chang
3d5c184acc Merge pull request #949 from rstudio/joe/feature/shared-brush-id
Allow shared brush IDs
2015-09-09 15:48:43 -05:00
Joe Cheng
9e03b17498 Add 'grunt clean' to delete shiny build artifacts 2015-09-09 12:19:43 -07:00
Joe Cheng
129714b044 Allow shared brush IDs 2015-09-09 12:12:47 -07:00
Joe Cheng
67823556d2 Merge pull request #939 from yihui/bugfix/selectize-selected
Fixes #929: defer setValue() for selectize until the options have been loaded from server
2015-09-09 12:10:03 -07:00
Yihui Xie
273e71e3c4 run grunt 2015-09-09 13:38:51 -05:00
Yihui Xie
076ac26929 call setValue() only once
otherwise every time an Ajax response is returned (e.g. during searching), the value is set to data.value
2015-09-09 13:29:37 -05:00
Yihui Xie
5a022b0a2c upgrade selectize.js from 0.11.2 to 0.12.1 to fix the ordering issue in #929
also fixes #865
2015-09-09 13:29:37 -05:00
Yihui Xie
9ab493a81f make sure mop is numeric
it is funny that head(1:11,'100') produces a bunch of NA's, but  head(1:11,'12') does not
2015-09-09 13:29:37 -05:00
Yihui Xie
dfc1f32595 Fixes #929: defer setValue() for selectize until the options have been loaded from server
Previously I was using a hack to set the selected value of selectize, i.e. add the selected option(s) to selectize via addOptions() (because the selected option(s) may not have existed); this hack can be removed and we can set the value in the `success` callback of the Ajax request, by which time the options will be available
2015-09-09 13:29:37 -05:00
Joe Cheng
e6fd30fb78 Merge pull request #935 from yihui/doc/events-vignette
Add a package vignette for the JS events
2015-09-09 10:33:52 -07:00
Joe Cheng
c8d338912a Merge pull request #918 from rstudio/joe/bugfix/binding-getid
Fix #676: getId(el) not being used in output binding
2015-09-09 10:33:45 -07:00
Winston Chang
d9d9e0b33f Add info about printing ggplot objects 2015-09-08 15:07:40 -05:00
Yihui Xie
1da7b83956 Bump version 2015-09-04 20:54:30 -05:00
Yihui Xie
29c545d2e3 Bump fontawesome version after #932 2015-09-04 20:53:54 -05:00
Joe Cheng
431b345c82 Fix #676: getId(el) not being used in output binding 2015-09-04 15:14:04 -07:00
Joe Cheng
8773b1b38f Merge pull request #946 from yihui/bugfix/recalculating
Typo: name -> message.name
2015-09-04 14:53:43 -07:00
Yihui Xie
52efb3dc16 Typo: name -> message.name 2015-09-04 15:43:21 -05:00
Yihui Xie
9ccd179b04 document the rest of events: shiny:conditional, shiny:visualchange, shiny:recalculating, shiny:recalculated 2015-09-04 15:09:34 -05:00
Joe Cheng
a8b35c49a7 Merge pull request #932 from dselivanov/master
Bump fontawesome version to 4.4.0, fixes #913
2015-09-04 12:15:31 -07:00
Peter K. Shultz
4e027f1a45 Update README.md
Add missing period.
2015-09-04 12:13:28 -07:00
Joe Cheng
119182454b Merge pull request #943 from yihui/feature/events-more
Events shiny:visualchange, shiny:conditional, and shiny:recalculating
2015-09-04 11:34:48 -07:00
Yihui Xie
04e10a4f0d Run grunt 2015-09-02 12:30:22 -05:00
Yihui Xie
4e5c5f9c5b Move the shiny:conditional event to the top of $updateConditionals() 2015-09-02 12:29:37 -05:00
Yihui Xie
1ee2a25eca Trigger the recalculating event on null when the binding does not exist 2015-09-02 12:29:01 -05:00
Yihui Xie
838e132515 Trigger shiny:visualchange in doSendOutputHiddenState() as well. Added a 'visible' property to the event object. 2015-08-31 17:07:11 -05:00
Yihui Xie
da76a843ee DO not assume '# + message.name' is the element id. Find the element through this.$bindings[name].el instead. 2015-08-31 17:02:14 -05:00
Yihui Xie
b0676b8b31 Trigger shiny:recalculated after the calculation is done 2015-08-31 16:38:46 -05:00
Yihui Xie
83c3656d29 Events shiny:visualchange, shiny:conditional, and shiny:recalculating 2015-08-31 15:58:05 -05:00
Yihui Xie
5ddd6cc94e add a summary section to the events vignette 2015-08-27 23:21:36 -05:00
Yihui Xie
90419765af Merge pull request #938 from yihui/bugfix/933
Fixes #933: make sure type is of length one
2015-08-26 11:27:05 -05:00
Yihui Xie
acad9354a6 Fixes #933: make sure type is of length one 2015-08-26 10:48:38 -05:00
Yihui Xie
9105dd7b04 Add a package vignette for the JS events 2015-08-24 15:25:58 -05:00
Joe Cheng
71adee1f38 Merge pull request #930 from yihui/feature/events
More JS events
2015-08-24 12:50:10 -07:00
Yihui Xie
3cbe3831ec Run grunt 2015-08-21 16:19:02 -05:00
Yihui Xie
619aa4f05a Events shiny:busy and shiny:idle
Keep track of the number of observer callbacks during addPendingFlush() and executeFlushCallbacks(). Send a custom message when the number is 0.
2015-08-21 16:12:45 -05:00
Yihui Xie
4df37d6f3e The shiny:updateinput event for inputs 2015-08-21 16:10:01 -05:00
Yihui Xie
58f8b482f5 The message object may be exactly false (or a falsy value), in which case shiny will fail to send the message to the handler. Use .hasOwnProperty() instead. 2015-08-21 16:09:25 -05:00
Yihui Xie
168f5e32af The shiny:message event 2015-08-21 16:08:16 -05:00
Yihui Xie
06bf28f10c Events shiny:value and shiny:error for outputs 2015-08-21 16:07:33 -05:00
Yihui Xie
620fdc0d9f The shiny:inputchanged event 2015-08-21 16:06:56 -05:00
Yihui Xie
bdac0e2456 Events shiny:bound and shiny:unbound for inputs and outputs 2015-08-21 16:06:00 -05:00
Dmitry Selivanov
60a57a0a40 Bump fontawesome version to 4.4.0, fixes #913 2015-08-20 12:34:52 +03:00
Yihui Xie
a242ae3849 Merge pull request #920 from yihui/yihui/selectize-dragdrop
fixes #902: add jQueryUI dependency when the drag_drop plugin is used in selectize
2015-08-06 21:46:30 -05:00
Yihui Xie
ced4060b5c fixes #902: add jQueryUI dependency when the drag_drop plugin is used in selectize 2015-08-06 16:59:51 -05:00
Winston Chang
0b3eb7a237 Merge tag 'v0.12.2'
Shiny 0.12.2
2015-08-05 15:08:21 -05:00
Winston Chang
c82f87cd76 Fix NEWS formatting 2015-08-04 23:05:30 -05:00
Winston Chang
51d8a6d9bf Bump version to 0.12.2 2015-08-04 23:00:34 -05:00
Winston Chang
d334aa2088 Merge branch 'http-head' 2015-08-04 22:59:49 -05:00
Winston Chang
710e003bdc Update httpuv version 2015-08-04 22:59:26 -05:00
Winston Chang
b2f5b4f861 Update NEWS 2015-08-04 22:58:21 -05:00
Winston Chang
0ac87930c8 Add support for HTTP HEAD requests 2015-08-04 22:58:21 -05:00
Winston Chang
241a482236 Add explicit namespace to non-base functions 2015-08-04 12:30:41 -05:00
Winston Chang
2abaffafcf Move imageOutput docs to plotOutput 2015-08-04 12:23:06 -05:00
Winston Chang
4545fedf31 Update NEWS 2015-08-03 16:05:39 -05:00
Joe Cheng
a47a690a68 Merge pull request #909 from rstudio/joe/bugfix/runGist
Fix runGist
2015-07-22 14:08:05 -07:00
Joe Cheng
f89c44e899 Fix runGist
Looks like GitHub changed the format of gist downloads from .tar.gz
to .zip
2015-07-22 10:30:57 -07:00
Winston Chang
59b0df5c82 Concat and minify shiny.js 2015-07-21 13:01:16 -05:00
Yihui Xie
5ec6ffb30a Merge pull request #905 from rstudio/joe/doc-tweaks
Doc tweaks (fixes #898)
2015-07-21 12:51:28 -05:00
Winston Chang
5956d2009c Minor code cleanup in slider JS code 2015-07-21 12:32:40 -05:00
Winston Chang
d9c7f21c02 Make updateSliderInput work with date/datetimes. Fixes #904 2015-07-21 12:32:18 -05:00
Winston Chang
926e508b8d Fix updateSliderInput example code 2015-07-21 12:31:31 -05:00
Winston Chang
ac83772945 Don't use scientific notation for sending slider values 2015-07-21 12:31:17 -05:00
Joe Cheng
cddf5cf70f Doc tweaks 2015-07-21 10:15:04 -07:00
Winston Chang
d53acdb46a Update NEWS 2015-07-20 14:14:38 -05:00
Winston Chang
cfae8f4fc6 Update to ion.rangeSlider 2.0.12 2015-07-20 14:09:26 -05:00
Joe Cheng
74cd4cecbf Merge remote-tracking branch 'yihui/feature/events'
Conflicts:
	inst/www/shared/shiny.js
	inst/www/shared/shiny.js.map
	inst/www/shared/shiny.min.js
	inst/www/shared/shiny.min.js.map
2015-07-16 10:24:49 -07:00
Joe Cheng
3e9e6a1389 Merge pull request #885 from rstudio/slider-improvements
Slider improvements
2015-07-16 10:21:25 -07:00
Joe Cheng
9788450c08 Merge pull request #874 from wch/file-remove
Remove uploaded files when session ends. Fixes #798
2015-07-16 10:02:27 -07:00
Yihui Xie
10b27aed34 grunt build and bump version 2015-07-14 13:52:49 -05:00
Joe Cheng
64f95be828 Merge pull request #892 from yihui/feature/events-connect
Events shiny:connected and shiny:disconnected
2015-07-14 11:35:49 -07:00
Yihui Xie
a54634023b trigger shiny:connected when the socket is opened and shiny:disconnected when it is closed 2015-07-14 13:22:55 -05:00
Winston Chang
9d942b78ef Merge pull request #881 from yihui/updateNavbarPage
Add two aliases of updateTabsetPanel(): updateNavbarPage() and updateNavlistPanel()
2015-07-03 11:00:33 -05:00
Winston Chang
4cd5357241 Set dragRange=TRUE as the default 2015-07-02 20:25:42 -05:00
Winston Chang
f985a96988 Concat and minify shiny.js 2015-07-02 16:50:43 -05:00
Winston Chang
0e3938da79 Add timezone support 2015-07-02 16:50:43 -05:00
Winston Chang
ec9bfc4731 sliderInput: add timeFormat argument 2015-07-02 16:50:43 -05:00
Winston Chang
9b91ebb8d2 Add strftime Javascript library 2015-07-02 16:50:43 -05:00
Winston Chang
da3f2367d7 Add range dragging functionality 2015-07-02 16:50:43 -05:00
Winston Chang
17cdeec34b Add Date and POSIXt support to sliders 2015-07-02 16:50:43 -05:00
Winston Chang
3446afd087 Move input handlers to separate file 2015-07-02 16:50:43 -05:00
Winston Chang
b12fef652c Update to ionRangeSlider 2.0.10 2015-07-02 16:50:43 -05:00
Winston Chang
21c7193281 Remove unneeded copy of normalize.css 2015-07-02 12:48:16 -05:00
Yihui Xie
a5e64274a2 Add two aliases of updateTabsetPanel(): updateNavbarPage() and updateNavlistPanel()
https://groups.google.com/d/msg/shiny-discuss/8VctqPqeurw/uAQIBvA1CpAJ
2015-07-02 01:37:14 -05:00
Winston Chang
3817202875 Make sure that directory removal is safe 2015-07-01 13:41:54 -05:00
Winston Chang
874fcb12a1 Remove uploaded files when session ends. Closes #798 2015-07-01 13:32:06 -05:00
Winston Chang
e0c5783703 Refactor fileUpoadContext to use private members 2015-07-01 13:32:05 -05:00
Winston Chang
a57e037b05 Fix docs for submitButton 2015-06-26 16:40:32 -05:00
Winston Chang
8546918cbb Merge pull request #873 from wch/input-width
Add width option to input functions
2015-06-18 13:14:54 -05:00
Winston Chang
82284029f2 Update NEWS 2015-06-18 13:12:49 -05:00
Winston Chang
7c20e865a5 Add width option to input functions. Closes #834, closes #589 2015-06-18 13:12:49 -05:00
Winston Chang
79267d4e12 Move input functions to separate files 2015-06-18 10:47:00 -05:00
Winston Chang
50aeb70597 Update NEWS with changes from 0.12.1 2015-06-18 10:46:26 -05:00
Joe Cheng
1d22a79074 Bump version 2015-06-15 08:47:49 -07:00
Joe Cheng
7f442f4206 Un-deprecate data table functions until DT stabilizes 2015-06-11 23:27:21 -07:00
Yihui Xie
985326989c Bump version after #857 2015-06-11 00:09:13 -05:00
Joe Cheng
be8f2afa37 Merge pull request #857 from rstudio/joe/bugfix/rebind
Fix #856: Outputs can not be unbound and re-bound
2015-06-08 18:08:19 -07:00
Joe Cheng
98882984b4 Fix #856: Outputs can not be unbound and re-bound 2015-06-08 16:56:08 -07:00
Winston Chang
a6cd0fdb85 Update NEWS 2015-06-03 14:03:16 -05:00
Winston Chang
7bc5ba7e9a Merge pull request #852 from rstudio/slider-motion
Slider fixes
2015-06-03 13:47:51 -05:00
Winston Chang
37e552cd36 Move sliderInput code into separate file 2015-06-02 15:36:03 -05:00
Winston Chang
51e2a4de7d Concat and minify shiny.js 2015-06-02 14:14:54 -05:00
Winston Chang
91ce2fcb06 Remove no-longer-needed workaround 2015-06-02 14:14:54 -05:00
Winston Chang
925a379702 Don't overshoot end of slider
This previously resulted in a bug where the animation would loop even if
loop=FALSE.
2015-06-02 14:14:54 -05:00
Winston Chang
3153cfd0ff Move both handles when animating double sliders 2015-06-02 14:14:54 -05:00
Winston Chang
ac8831b4c7 Use methods() instead of .S3methods(). Fixes #849
The .S3methods() function was introduced in R 3.2.0, so this code was broken
on older versions of R.
2015-06-02 14:14:31 -05:00
Joe Cheng
acc535e1a4 Merge pull request #850 from rstudio/min-option
Add shiny.minified option for minified JavaScript. Closes #826
2015-06-01 21:54:33 -07:00
Winston Chang
fdacb4fe7d Add shiny.minified option for minified JavaScript. Closes #826 2015-06-01 20:58:10 -05:00
Winston Chang
fc7208469d Add staticdocs entries for interactive plots 2015-05-26 22:44:26 -05:00
Winston Chang
5c38cb733a Safer method for finding which method would be called 2015-05-26 17:05:10 -05:00
Winston Chang
515a67a320 Don't attempt to extract coordmap when print.ggplot is not used (#841) 2015-05-21 17:00:51 -05:00
Winston Chang
941348f1db Override print.ggplot method in renderPlot. Fixes #841 2015-05-21 16:45:39 -05:00
Joe Cheng
8d7752b0bc Merge pull request #840 from rstudio/joe/bugfix/methods-depend
Depend on methods so Rscript doesn't fail
2015-05-21 09:57:50 -07:00
Joe Cheng
15af660424 Depend on methods so Rscript doesn't fail 2015-05-21 09:56:16 -07:00
Joe Cheng
790555ae89 Bump version, NEWS 2015-05-20 14:35:04 -07:00
Joe Cheng
3cc4df4e29 Merge pull request #837 from rstudio/joe/bugfix/callbacks-fifo
Ensure that callbacks fire in a FIFO order
2015-05-20 14:32:46 -07:00
Joe Cheng
395d1cee70 Ensure that callbacks fire in a FIFO order
Version bump required so Leaflet can detect this fix
2015-05-20 13:29:56 -07:00
Yihui Xie
89bc7efbca query$field is either an atomic vector, or a matrix, so use c() to coerce the result to a vector (previously RJSONIO::fromJSON() would return a list, but now jsonlite returns a matrix) 2015-05-20 12:44:13 -05:00
Yihui Xie
8f893a9752 bump version 2015-05-19 16:15:24 -05:00
Yihui Xie
54e02e412c make sure q$search[['value']] is not of length zero 2015-05-19 16:14:30 -05:00
Winston Chang
808d7aab3f Merge tag 'v0.12.0'
Shiny 0.12.0 released to CRAN
2015-05-19 09:52:19 -05:00
Winston Chang
24a8f8f38b Merge pull request #830 from rstudio/check-htmlwidgets
Check htmlwidgets version
2015-05-18 11:58:48 -05:00
Winston Chang
90c00bed2f Check htmlwidgets version 2015-05-18 11:56:02 -05:00
Winston Chang
054c911a1f Clear cran comments 2015-05-18 11:07:42 -05:00
Winston Chang
c2d5432a5d Bump version to 0.12.0 2015-05-18 10:10:53 -05:00
Winston Chang
dd64b70f5b Concat and minify shiny.js 2015-05-18 09:49:10 -05:00
Yihui Xie
a69dbeb10f bump version 2015-05-17 15:20:16 -05:00
Yihui Xie
976a768446 white spaces 2015-05-17 15:19:04 -05:00
Yihui Xie
5612cec91f Merge pull request #829 from yihui/deprecate-datatables
closes #807: add messages of deprecation for DataTables in shiny
2015-05-17 15:17:51 -05:00
Yihui Xie
46996eb81c closes #807: add messages of deprecation for DataTables in shiny 2015-05-15 18:21:58 -05:00
Winston Chang
12990f9fb2 Merge pull request #823 from yihui/bugfix/814
Load selectize options after initialization in the server mode
2015-05-15 15:22:39 -05:00
Yihui Xie
77ff988232 a news item for the change in server-side selectize 2015-05-15 15:17:31 -05:00
Yihui Xie
8df98c29b8 this comment is no longer true 2015-05-15 15:06:23 -05:00
Yihui Xie
7554f8395b fixes #814: load options after initialization of selectize in the server mode 2015-05-15 15:05:39 -05:00
Winston Chang
6fc0bac106 Properly use hoverClip option 2015-05-13 11:42:18 -05:00
Winston Chang
d252feddc9 Change nullOutside default to TRUE 2015-05-13 11:16:48 -05:00
Winston Chang
8c2645498d Merge pull request #824 from rstudio/interaction-tweaks
Interaction tweaks
2015-05-13 11:14:46 -05:00
Winston Chang
528acc4aa4 Concat and minify shiny.js 2015-05-13 11:08:47 -05:00
Winston Chang
2ce45eab06 Hovering: add option to send NULL when mouse is outside 2015-05-13 11:08:16 -05:00
Winston Chang
074c24aa10 Show brush only after mouse starts moving 2015-05-11 22:31:56 -05:00
Winston Chang
79e4007732 Add option to return all selected rows for mouse interactions 2015-05-11 15:56:34 -05:00
Winston Chang
742ce6673c Re-document with roxygen2 4.1.1 2015-05-11 15:55:51 -05:00
Winston Chang
4a74f588b9 nearPoints: add _dist column even when zero rows selected 2015-05-05 23:11:33 -05:00
Winston Chang
f876dc066c Minify shiny.js 2015-05-05 23:11:33 -05:00
Winston Chang
65aaf386c2 Lock grunt-contrib-uglify version
Version changes of the grunt-contrib-uglify version can result in different
min.js output. Lock it so the minified files won't have spurious changes.
2015-05-05 23:01:24 -05:00
Winston Chang
4eae6bd362 Update NEWS 2015-05-01 14:59:23 -05:00
Joe Cheng
4f7cfd6bd4 Bump dev version for ggplot2 interactive graphics 2015-05-01 09:53:46 -07:00
Joe Cheng
1136ad09ee Merge pull request #802 from rstudio/interact-ggplot
BOOM!!!!
2015-05-01 09:51:51 -07:00
Winston Chang
4a67bd945c Concat and minify shiny.js 2015-05-01 11:29:31 -05:00
Winston Chang
a2841f7cf2 Allow selectBrush to operate in just x or y direction 2015-05-01 11:28:43 -05:00
Winston Chang
4fa6e9dafe Fix off-by-one positioning error for base graphics 2015-05-01 11:28:43 -05:00
Winston Chang
7ebd7959f9 Document data structures for plot interactions 2015-05-01 09:58:00 -05:00
Winston Chang
4386015cff brushedPoints and nearPoints: handle Dates and POSIXt properly 2015-05-01 09:56:24 -05:00
Winston Chang
5cd014f7e6 Fix restoring brush with new coordmap panel data format 2015-05-01 09:56:24 -05:00
Winston Chang
30d0bfbdf0 Rename selectBrush to brushedPoints 2015-05-01 09:56:24 -05:00
Joe Cheng
48cfeca220 Merge pull request #797 from rstudio/joe/input-logging
Add session$onInputReceived
2015-04-30 22:10:21 -07:00
Winston Chang
5fefc48a0b Fix variable name 2015-04-29 13:19:46 -05:00
Winston Chang
42f2ae16ec Document missing argument 2015-04-29 13:19:46 -05:00
Winston Chang
3d47b0201f Simplify selectBrush and nearPoints code 2015-04-29 12:17:28 -05:00
Winston Chang
7607b1215f Update tests 2015-04-29 11:49:36 -05:00
Winston Chang
eae2b40898 Add nearPoints() function 2015-04-29 11:48:33 -05:00
Winston Chang
8e253046d8 Merge pull request #813 from pvictor/master
Change in sliderInput
2015-04-29 10:37:02 -05:00
pvictor
b0e17f02b5 Change in sliderInput
Add `animate$playButton` and `animate$pauseButton` in `sliderTag` to add possibility to custom button with `animateOptions`
2015-04-29 15:30:25 +02:00
Winston Chang
3f3c131737 Automatically find var names for brush selection 2015-04-27 17:04:07 -05:00
Winston Chang
2b227fcca5 Send variable mappings in coordmap 2015-04-27 15:22:43 -05:00
Winston Chang
639e55b537 Rename underBrush to selectBrush 2015-04-25 18:00:11 -04:00
Winston Chang
8386404b25 Capture and display coordmap errors 2015-04-25 09:38:40 -04:00
Winston Chang
a093afb630 More informative comments 2015-04-23 11:53:31 -05:00
Winston Chang
7208688128 Simplify facet code 2015-04-23 11:53:31 -05:00
Winston Chang
b94d406bd9 Treat shiny.js as binary 2015-04-23 11:53:31 -05:00
Winston Chang
79188b7d62 Add underBrush() function 2015-04-23 11:53:31 -05:00
Winston Chang
85b2fc503d Make brush div 1px larger 2015-04-20 15:06:00 -05:00
Winston Chang
57f33109b2 Change default brush color to blue 2015-04-20 15:06:00 -05:00
Winston Chang
d039547886 Fixes for R CMD check in R 3.2.0 2015-04-20 11:55:31 -05:00
Winston Chang
55621b7826 Use NULL for session$user and $groups 2015-04-17 13:23:50 -05:00
Winston Chang
854730f258 Fix restoring brush with facets in IE8/9 2015-04-17 12:15:38 -05:00
Winston Chang
9c4f73f314 Respect falsy opts for imageOutput 2015-04-16 23:43:20 -05:00
Winston Chang
e1fa491af7 Fix panel matching logic 2015-04-16 23:40:08 -05:00
Winston Chang
b909a3e05c Allow brush resizing 2015-04-16 23:40:07 -05:00
Winston Chang
4159c539e7 Consolidate code for width/height 2015-04-16 23:40:07 -05:00
Winston Chang
d1bd232ec7 Grunt: jshint before uglify 2015-04-16 23:40:07 -05:00
Winston Chang
a47898a2c4 Fix min/max order for reversed scales 2015-04-16 23:40:07 -05:00
Winston Chang
06b69e516a Pixelratio workaround 2015-04-16 23:40:07 -05:00
Winston Chang
312c89aaee Fix panel scale order for facet_grid 2015-04-16 23:40:07 -05:00
Winston Chang
a5b1f020ae Simplify sendBrushInfo 2015-04-16 23:40:07 -05:00
Winston Chang
e9cd1bef43 Send brush data when reset 2015-04-16 23:40:07 -05:00
Winston Chang
7b17ce5de1 Fix brush import for reverse scales 2015-04-16 23:40:07 -05:00
Winston Chang
ffb1b06bf4 Use 'expand' parameter 2015-04-16 23:40:06 -05:00
Winston Chang
21e9ffec97 Cleaner coordmap initialization 2015-04-16 23:40:06 -05:00
Winston Chang
7cfaa2adfc Move clipToBounds from coordmap to panel 2015-04-16 23:40:06 -05:00
Winston Chang
4e80e35976 Get correct coordinates for panels 2015-04-16 23:40:06 -05:00
Winston Chang
e9f78f6ace Restore brush even when scales change 2015-04-16 23:40:06 -05:00
Winston Chang
4d074c6fa9 Fix log scaling 2015-04-16 23:40:06 -05:00
Winston Chang
0b3c2e198e Add functions to coordmap object 2015-04-16 23:40:06 -05:00
Winston Chang
48cd7200cc Partial implementation of scale/inv 2015-04-16 23:40:06 -05:00
Winston Chang
d925702b98 Fix height/width calculation of brush div 2015-04-16 23:40:06 -05:00
Winston Chang
55cbd72a47 Gruntfile: add watch support for concat 2015-04-16 23:40:06 -05:00
Winston Chang
fbf1ba172f Implement client-side support for facets 2015-04-16 23:40:05 -05:00
Winston Chang
abb722f405 Fix bottom/top reversal 2015-04-16 23:40:05 -05:00
Winston Chang
2c121dc2c3 Put shiftToRange in right place 2015-04-16 23:40:05 -05:00
Winston Chang
dbcdbda2ef Modularize brush code 2015-04-16 23:40:05 -05:00
Winston Chang
03784ba82e Partial refactoring of brush 2015-04-16 23:40:05 -05:00
Winston Chang
04768ad8fa Encode facet information 2015-04-16 23:40:05 -05:00
Winston Chang
29943408e5 Consolidate coordinate functions 2015-04-16 23:40:05 -05:00
Winston Chang
dbadc05bef Better function name 2015-04-16 23:40:05 -05:00
Winston Chang
2e6347b380 Safe handling of discrete scales 2015-04-16 23:40:05 -05:00
Winston Chang
6c65b1ffde Add support for ggplot2 log coord transforms 2015-04-16 23:40:05 -05:00
Winston Chang
358416687f Add support for ggplot2 log scales 2015-04-16 23:40:04 -05:00
Winston Chang
1dc061e1c6 Add support for ggplot2 reversed scales 2015-04-16 23:40:04 -05:00
Winston Chang
e7f2572f42 Treat minified JS and map files like binary 2015-04-16 23:40:04 -05:00
Winston Chang
463ee7e027 Add click/hover/brush support for ggplot2 2015-04-16 23:40:04 -05:00
Winston Chang
667bc95d02 Rename coordmap usr and bounds to domain and range 2015-04-16 23:40:04 -05:00
Winston Chang
3f8cc71814 Use separate function for getting coordmap 2015-04-16 23:40:04 -05:00
Winston Chang
a9a6e96a6a Move renderPlot into separate file 2015-04-16 23:40:04 -05:00
Winston Chang
02caf05aaf Fix formatting in flowLayout documentation 2015-04-14 11:04:50 -05:00
Joe Cheng
da88678a43 Merge pull request #796 from mikelove/patch-1
flowLayout's man page: % needs to be escaped
2015-04-14 09:03:15 -07:00
Mike Love
1e8a9de60a flowLayout's man page: % needs to be escaped
or else it turns into a commend in the Rd file
2015-04-14 11:51:38 -04:00
Joe Cheng
1a6181cb15 Merge pull request #778 from rstudio/bugfix/clear-select-choices
Allow updateSelectInput(choices=character(0)) to clear select choices
2015-04-14 08:42:53 -07:00
Yihui Xie
ece69342b8 bump version 2015-04-13 10:09:59 -05:00
Yihui Xie
fe601d631b bump version of mime to 0.3
due to the fact that mime < 0.3 used GPL but copied code from Rook, which is specifically GPL-2; mime >= 0.3 also uses GPL-2 since GPL implies 2 or 3, and 3 does not work with 2
2015-04-13 10:09:26 -05:00
Yihui Xie
42d2e5aaef bump version requirement of jsonlite due to toJSON(json_verbatim = TRUE) (#795) 2015-04-13 10:06:39 -05:00
Winston Chang
bac7ab7f01 Merge pull request #795 from yihui/feature/verbatim-json
Treat the output of toJSON() as a verbatim JSON string
2015-04-09 10:29:46 -05:00
Yihui Xie
c6ac1474d4 Treat the output of toJSON() as a verbatim JSON string, and do not double-encode it
https://github.com/jeroenooms/jsonlite/commit/6fd201b3ad

also see ramnathv/htmlwidgets#28
2015-04-08 21:38:15 -05:00
Winston Chang
5a9c4ad8f3 Reinstate image error message fix
This fix for #783 seems to have gotten lost when shiny.js was split up.
2015-04-08 10:01:45 -05:00
Winston Chang
babc59f85c Clarifcations in tools README 2015-03-30 20:00:13 -05:00
Winston Chang
982a4361cd Merge pull request #775 from rstudio/split-js
Split up shiny.js into multiple files
2015-03-30 16:20:05 -05:00
Winston Chang
15e53ca55e Remove extraneous indenting 2015-03-30 16:18:26 -05:00
Winston Chang
ceb428b8bd Split up shiny.js 2015-03-30 16:17:04 -05:00
Winston Chang
b7fe3ed745 Update to ionRangeSlider 2.0.6. Closes #777 2015-03-27 15:31:37 -05:00
Winston Chang
817b614e61 Clear error messages in imageOuputs. Fixes #783 2015-03-27 15:11:35 -05:00
Joe Cheng
3321e95b54 Add session$onInputReceived 2015-03-26 16:04:04 -07:00
Winston Chang
fd5f536d14 Use jsonlite 0.9.15 2015-03-26 09:55:45 -05:00
Joe Cheng
fdbcb32be7 Allow updateSelectInput(choices=character(0)) to clear select choices 2015-03-24 13:00:00 -07:00
Winston Chang
a774cee1d9 Remove unused function 2015-03-21 22:19:58 -05:00
Winston Chang
1c46f227d2 Update travis config to use dev version of jsonlite 2015-03-20 15:28:36 -05:00
Winston Chang
6191c96347 Update NEWS 2015-03-20 15:13:49 -05:00
Winston Chang
12918fdfee Actually udpate jsonlite version 2015-03-20 15:13:39 -05:00
Winston Chang
8cea246fc8 Bump version to 0.11.1.9003 and increase jsonlite version dependency 2015-03-20 15:00:07 -05:00
Winston Chang
41455a008b Update toJSON for more RJSONIO compatibility 2015-03-20 14:58:28 -05:00
Winston Chang
be22d5c95d Merge branch 'interactive-graphic'
Conflicts:
	inst/www/shared/shiny.min.js
	inst/www/shared/shiny.min.js.map

Re-minified the shiny.min.js file in the merge.
2015-03-20 14:51:52 -05:00
Winston Chang
b298a62e46 Merge pull request #773 from yihui/feature/json-date
use ISO8601 and UTC for POSIX[c|l]t time by default
2015-03-20 11:06:57 -05:00
Winston Chang
839045ed66 Clear pending event on double click 2015-03-20 10:51:01 -05:00
Yihui Xie
a4a5c61fef use ISO8601 and UTC for POSIX[c|l]t time by default 2015-03-19 16:17:33 -05:00
Winston Chang
dd6aa9e4cf Minify shiny.js 2015-03-19 16:00:12 -05:00
Winston Chang
e299b51779 Simplify pending event tracking 2015-03-19 15:58:35 -05:00
Winston Chang
d3f0129c3f Expand region to start a brush 2015-03-19 15:49:25 -05:00
Winston Chang
ae938c66cc Add overview comments 2015-03-19 15:26:15 -05:00
Winston Chang
8d662f4f89 Add distance threshold for two clicks to count as a double-click 2015-03-19 15:06:48 -05:00
Winston Chang
a1caa41fe9 Simplify conversion of options to HTML properties 2015-03-19 13:55:13 -05:00
Winston Chang
6028263681 Fix some simple issues from pull request feedback 2015-03-18 20:16:06 -05:00
Winston Chang
30f9291496 Update documentation 2015-03-17 13:08:05 -05:00
Winston Chang
2400a44ded Minify shiny.js 2015-03-17 12:43:44 -05:00
Winston Chang
952556a9d1 Add option to reset brush on new image 2015-03-17 12:40:20 -05:00
Winston Chang
2e18b5c64b Fix indentation 2015-03-17 12:40:20 -05:00
Winston Chang
cb499c6105 Remove no-longer-needed IE9/10 workaround 2015-03-16 22:35:31 -05:00
Winston Chang
7f87bcddc1 Rename file 2015-03-16 22:28:00 -05:00
Winston Chang
6798917bc9 Simplify namespacing of image interaction events 2015-03-16 22:25:18 -05:00
Winston Chang
cf3f32ac37 Add dblclick workaround for IE8 2015-03-16 22:00:41 -05:00
Winston Chang
a41e1dafc2 Add IE version detection code 2015-03-16 22:00:23 -05:00
Winston Chang
3ac5124e5c Make sure a double click doesn't trigger click event 2015-03-16 21:27:13 -05:00
Winston Chang
83a472794b Add double-click event 2015-03-16 19:44:40 -05:00
Winston Chang
af78d62b76 Change click/hover/brush arguments 2015-03-16 16:05:50 -05:00
Winston Chang
27a0708909 Add left/right or top/bottom borders for x or y brushing 2015-03-16 14:27:05 -05:00
Winston Chang
5ab58f86ba Change event listener bindings fo IE8 compatibility
Binding mousemove event listeners to the window apparently doesn't work in IE8,
so bind to document instead.
2015-03-16 13:49:45 -05:00
Winston Chang
2c0bfdccf9 Restructure brushing and dragging event handlers 2015-03-16 12:52:52 -05:00
Winston Chang
581618370b Remove unnecessary code 2015-03-16 12:52:51 -05:00
Winston Chang
bdf217c45a Reorganize event handlers so they work properly in IE<=10 2015-03-16 12:52:51 -05:00
Winston Chang
42d6594159 Fix drag and selection on IE 2015-03-13 16:26:56 -05:00
Winston Chang
fac1750b63 Document direction argument for brushOptions 2015-03-13 16:09:52 -05:00
Winston Chang
6907d192f5 Allow mousemove and mouseup outside of the image 2015-03-13 14:32:23 -05:00
Winston Chang
0380f36489 Make sure bounds are constrained to plotting region 2015-03-13 13:48:19 -05:00
Winston Chang
1524dc2680 Add x and y brushing
This also contains a big refactoring of the brushing code.
2015-03-13 12:49:59 -05:00
Winston Chang
c95cc0a52b Better function name 2015-03-11 23:13:25 -05:00
Winston Chang
a876c5a888 Fix plotting region check 2015-03-11 23:09:51 -05:00
Winston Chang
bdd925886a Show grab and grabbing cursor with brush 2015-03-11 23:09:51 -05:00
Winston Chang
4d3d292add Only respond to left mouse button 2015-03-11 15:58:13 -05:00
Winston Chang
48f03e79e2 Add brushOptions and hoverOptions functions
Also clean up help for imageOutput and plotOutput, and add examples.
2015-03-11 15:37:22 -05:00
Winston Chang
e3af622a36 Replace bind() with explicit function wrappers 2015-03-11 12:25:45 -05:00
Winston Chang
dcb300ab50 Merge pull request #763 from rstudio/joe/bugfix/slider-delay
Fix 250ms delay in updateSliderInput(value=...) roundtrip.
2015-03-11 00:17:08 -05:00
Winston Chang
95ffd46a63 Clear click/brush/hover values when new image is received 2015-03-10 23:19:25 -05:00
Winston Chang
6f5d4a8620 Fix off-by-one error in plot pixel coordinates 2015-03-10 22:48:57 -05:00
Winston Chang
62855cc969 Fix clipping bounds off-by-one error 2015-03-10 22:42:55 -05:00
Winston Chang
bdfe9dfab2 Fix bug where brush goes outside 2015-03-10 22:42:55 -05:00
Joe Cheng
465ddf1a01 Fix 250ms delay in updateSliderInput(value=...) roundtrip. 2015-03-10 15:17:40 -07:00
Winston Chang
18a4ac1653 Refactor click and hover handlers to use shared function 2015-03-10 16:52:27 -05:00
Winston Chang
76d55144c5 Add clip option for click, hover, and brush 2015-03-10 16:23:27 -05:00
Winston Chang
665590a2f9 Add isPending method to Throttler 2015-03-10 15:32:12 -05:00
Winston Chang
81aa9a31c6 Don't send brush info second time on mouseup 2015-03-10 14:34:57 -05:00
Winston Chang
082490708f Consolidate image output options 2015-03-10 14:26:14 -05:00
Winston Chang
20ca4f8260 Add debounce and throttle options to brush 2015-03-10 14:16:38 -05:00
Winston Chang
eda057eb07 Disable image dragging when brushing in Firefox 2015-03-10 13:31:32 -05:00
Winston Chang
aed31c0eba Simplify image render logic
Now this exits early if data is empty.
2015-03-10 11:10:25 -05:00
Winston Chang
ea585458c7 Fix offset calculation for brush dragging 2015-03-10 10:48:51 -05:00
Winston Chang
e226e1c045 Add click/hover/brush support to imageOutputs 2015-03-10 10:47:03 -05:00
Winston Chang
ef330dd613 Formatting tweaks 2015-03-10 09:52:09 -05:00
Winston Chang
1225560ccd Streamline hover handler 2015-03-10 09:52:09 -05:00
Winston Chang
eef184e6ef Use crosshair cursor for brush 2015-03-09 22:02:04 -05:00
Winston Chang
50337eb731 Get jQuery object just once 2015-03-09 22:01:46 -05:00
Winston Chang
77f5e7d581 Add ability to clear previous brush 2015-03-09 21:54:13 -05:00
Winston Chang
02118bac76 Add brush dragging 2015-03-09 21:48:02 -05:00
Winston Chang
8b41be238a Refactor createBrushHandler 2015-03-09 20:39:31 -05:00
Winston Chang
8791e70c67 Add visible overlay for brush 2015-03-09 20:13:37 -05:00
Winston Chang
34a4b8f2d2 Add basic brushing support 2015-03-09 16:18:32 -05:00
Winston Chang
54c936b010 Refactor hover handler 2015-03-09 14:52:44 -05:00
Winston Chang
ed8d95e055 Move mouse coordinates to separate function 2015-03-09 14:17:12 -05:00
Winston Chang
25e8d080af Use lists instead of named vectors
jsonlite 0.9.14 drops names of named vectors, so we'll use lists instead.
2015-03-09 13:29:51 -05:00
Winston Chang
4599a7ab4e Merge pull request #759 from wch/fix-checkbox
Fix checkbox input binding (closes #206)
2015-03-06 15:03:58 -06:00
Winston Chang
5a106e0e6d Fix checkbox input binding (closes #206)
This fixes the bug introduced by #754.
2015-03-06 14:19:48 -06:00
Winston Chang
e4a211ba02 Send HTTP errors as UTF-8
This fixes an issue related to #736.
2015-03-06 10:27:30 -06:00
Joe Cheng
7ab373c942 Merge pull request #756 from rstudio/feature/port-option
Add shiny.port option
2015-03-06 01:41:00 -06:00
Winston Chang
18f1ebf715 Merge pull request #758 from yihui/DataTables1.10.5
upgrade DataTables to 1.10.5
2015-03-05 22:11:43 -06:00
Yihui Xie
2c02f44b26 upgrade DataTables to 1.10.5
need to be able to set $.fn.dataTableExt.errMode = 'none' to fix #561
2015-03-05 21:38:45 -06:00
Joe Cheng
8ae8168252 Merge pull request #754 from rstudio/remove-old-multiinput
Remove old multiInput code
2015-03-05 16:45:33 -06:00
Joe Cheng
c504f0b166 Merge pull request #755 from yihui/mimetype
remove the list of content types and use mime::guess_type()
2015-03-05 09:26:45 -06:00
Winston Chang
23da559d26 Add shiny.port option 2015-03-04 20:15:43 -06:00
Winston Chang
8b3ca12658 Mention app.R in runApp help 2015-03-04 20:11:16 -06:00
Yihui Xie
0f70b5662c remove the list of content types and use mime::guess_type()
also fixes #575
2015-03-04 19:58:37 -06:00
Winston Chang
475541cac0 Re-generate shiny.min.js 2015-03-04 19:43:54 -06:00
Winston Chang
007d6ad9c3 Simplify return value 2015-03-04 19:43:35 -06:00
Winston Chang
79db8d91ab Remove obsolete multiInput code (#206)
This commit removes multiInput code that was used for the HTML structure
generated in Shiny <= 0.5.0, and is now obsolete.
2015-03-04 19:39:53 -06:00
Joe Cheng
a0c6feb386 Merge pull request #753 from rstudio/bugfix/content-type
Fix downloading of files with no extension. Fixes #575
2015-03-04 16:23:30 -06:00
Winston Chang
1c72601123 Fix downloading of files with no extension. Fixes #575 2015-03-04 15:50:51 -06:00
Winston Chang
c6bcdd1ae1 Re-generate shiny.min.js 2015-03-04 15:09:28 -06:00
Winston Chang
e0acdba626 Remove unneeded ID attributes. Fixes #684
The checkboxGroup and radioButtons <input> items had an unneeded ID for the
DOM element, which could conflict with other items in the web page.
2015-03-04 15:07:38 -06:00
Winston Chang
a73e72f267 Add backward compatibility for shinysession$session (Fixes #752) 2015-03-04 11:13:52 -06:00
Joe Cheng
ee6682e7c8 Merge pull request #750 from rstudio/bugfix/nested-uioutput-duplicate-id
Fix issue #749: Nested uiOutputs break outputs
2015-03-04 09:10:56 -06:00
Joe Cheng
6c36ea5753 Fix issue #749: Nested uiOutputs break outputs 2015-03-03 21:28:47 -06:00
Winston Chang
3f798f1843 Update slider example for Shiny 0.11. (Fixes #748) 2015-03-02 16:54:35 -06:00
Winston Chang
4a806db8ae toJSON: special case for length-1 atomic vectors 2015-02-27 21:42:43 -06:00
Winston Chang
9c12125512 Bump version to 0.11.1.9002 2015-02-27 15:53:32 -06:00
Winston Chang
51130793fe Assign request object in self
The session object is now gone, so the appropriate place to assign `request`
is in `self`.
2015-02-27 15:34:55 -06:00
Winston Chang
d39c93ee7e Set up onEnd before calling onStart
This fixes an annoying bug where, if the app crashes while loading (for
example, if you call library() with a missing package), R ends up in the app's
working directory instead of in the original working directory.
2015-02-27 15:25:53 -06:00
Winston Chang
e1cfb29fa0 Update NEWS 2015-02-27 15:12:39 -06:00
Winston Chang
4dde16d836 Merge pull request #746 from rstudio/session-refactor
Refactor ShinySession object
2015-02-27 15:04:50 -06:00
Winston Chang
1c57ef5931 Remove leading dot from private item names 2015-02-27 15:02:09 -06:00
Winston Chang
0f642fe3ad Add class attribute to ShinySession object 2015-02-27 15:02:09 -06:00
Winston Chang
46844b516a Remove unneeded 'session' object
The 'session' object is no longer needed. Now that the ShinySession object
has proper public and private members, that object can be passed directly.
2015-02-27 15:02:09 -06:00
Winston Chang
b9cef228d9 Use explicit 'self', and make ShinySession portable 2015-02-27 15:02:09 -06:00
Winston Chang
fd71d04000 Use explicit 'private' 2015-02-27 15:02:09 -06:00
Winston Chang
bedb811621 Remove leading dots from public methods 2015-02-27 15:02:09 -06:00
Winston Chang
173736fd69 Set message encoding to UTF-8 instead of native (Fixes #742) 2015-02-27 14:55:31 -06:00
Winston Chang
21eea27c4a Remove duplicated 'destdir' documentation 2015-02-27 14:53:50 -06:00
Winston Chang
b39f04fbc3 Use native R config for travis 2015-02-27 11:43:30 -06:00
Winston Chang
04f898be21 Bump version to 0.11.1.9001 2015-02-23 16:43:48 -06:00
Winston Chang
defedda891 Switch from RJSONIO to jsonlite (again) 2015-02-23 16:41:36 -06:00
Winston Chang
bb2c8e5fd2 Clean up observeEvent and eventReactive examples 2015-02-23 15:57:27 -06:00
Winston Chang
7410bb9e9a Re-document 2015-02-23 15:57:06 -06:00
Winston Chang
fd3907596b Restore ability to dynamically set selectInput labels. Closes #741 2015-02-18 14:59:07 -06:00
Winston Chang
221a233ea4 Update NEWS 2015-02-12 13:21:16 -06:00
Winston Chang
389adda8ec Merge pull request #688 from xbhsu/feature/runURL-destination-file
Specifying destination file for runURL, runGist, and runGitHub
2015-02-12 13:11:19 -06:00
bhsu
835b65740b fixed consistency issues 2015-02-12 13:11:00 -05:00
Winston Chang
b24abffd0d Bump version to 0.11.1.9000 for development 2015-02-12 11:39:31 -06:00
Winston Chang
2ddf578f07 Add NEWS item 2015-02-12 11:39:05 -06:00
Yihui Xie
61b83c3e34 replace `` with \code{} in Rd 2015-02-11 18:12:14 +08:00
Winston Chang
3454ddbb2a Merge tag 'v0.11.1'
Shiny 0.11.1 released to CRAN
2015-02-10 19:42:58 -06:00
Winston Chang
194e4ca70d Update cran comments 2015-02-10 13:12:13 -06:00
Winston Chang
074981a709 Update Date in DESCRIPTION 2015-02-10 13:08:44 -06:00
Winston Chang
f157200a9f Fix Bootstrap URL 2015-02-10 10:58:31 -06:00
Winston Chang
f70fcddaad Clarify docs for shinyServer and shinyUI 2015-02-10 10:46:51 -06:00
Winston Chang
aa2129b60e Bump version to 0.11.1 2015-02-06 11:49:49 -06:00
Winston Chang
3794541828 Update gruntfile to watch for changes in DESCRIPTION 2015-02-06 11:49:30 -06:00
Winston Chang
b1a6dc65ba Remove jsonlite NEWS item 2015-02-06 11:23:50 -06:00
Winston Chang
040ae293fb Revert switch to jsonlite
This reverts commits deffc90, ab4dc64, and 0755579, returning to RJSONIO.
The purpose of this is to prepare for a maintenance release for 0.11
without the switch to jsonlite, to reduce the risk of new bugs.
2015-02-06 10:53:54 -06:00
Winston Chang
b74e93f3a4 Update NEWS and bump version 2015-02-05 15:51:01 -06:00
Winston Chang
dd3cc29af1 Merge pull request #728 from rstudio/bugfix/tab-value-with-icon
Fix #725: Tabs with icons give incorrect values
2015-02-05 15:44:02 -06:00
Joe Cheng
72b9a93088 Don't error when tabPanel has value but tabsetPanel doesn't have id
Causes problems now that tabPanel always has a value
2015-02-05 13:38:04 -08:00
Joe Cheng
4446f0a1f3 Merge pull request #729 from wch/feature/select-size
selectInput: add control for size (height)
2015-02-05 13:34:40 -08:00
Winston Chang
35802c12f6 selectInput: add control for size (height) 2015-02-05 15:30:03 -06:00
Winston Chang
f5fd30883a Update NEWS 2015-02-05 15:28:09 -06:00
Winston Chang
f8e720d6dc Fix tests for new HTML structure 2015-02-05 15:25:09 -06:00
Winston Chang
9f8f04caec selectInput: use form-control for multiple and single 2015-02-05 14:51:40 -06:00
Winston Chang
69aec85882 Fix label spacing for inline checkbox and radio 2015-02-05 12:46:54 -06:00
Winston Chang
e84012ec38 Update input docs to explain NULL label (#727) 2015-02-05 12:40:14 -06:00
Joe Cheng
128df6a2bf Fix #725: Tabs with icons give incorrect values
When no explicit value argument was present on tabPanel,
the inner text of the HTML anchor was used. This gave
weird results when an icon was used, since it appears in
the anchor.

The fix is to always use the value parameter, defaulting
it to the title.
2015-02-05 10:23:04 -08:00
Winston Chang
7b76951461 navbarPage: Don't include empty row when header=NULL. Fixes #722 2015-02-05 10:18:24 -06:00
Winston Chang
38d87450e6 Fix typo in docs 2015-02-05 10:17:42 -06:00
Winston Chang
b9c6b84ff5 selectInput: use BS 3 styling when multiple && !selectize. Closes #724 2015-02-04 19:45:04 -06:00
Winston Chang
5ba1d57b1f Update NEWS and bump version 2015-02-04 13:32:27 -06:00
Winston Chang
a4d567e44d Merge pull request #704 from wch/html-replace2
htmlOutput: allow custom container function
2015-02-04 13:30:19 -06:00
Joe Cheng
19a62ba7e9 Merge pull request #723 from rstudio/bugfix/namespace-filtering
Fix oversubscription of shown/hidden events
2015-02-04 10:20:42 -08:00
Winston Chang
65d6c7b558 Minify shiny.js 2015-02-04 12:17:30 -06:00
Winston Chang
8c828e7881 Correct event namespace filtering 2015-02-04 12:15:23 -06:00
Winston Chang
b711780688 Debounce sendImageSize 2015-02-04 12:15:23 -06:00
Joe Cheng
855cdc8eda Fix oversubscription of shown/hidden events
Bootstrap 3 shown/hidden events look like "shown.bs.modal",
"shown.bs.popover", etc. When subscribing to these events, you also
automatically pick up "shown" and "hidden" events. This causes a 6X
oversubscription of hidden and shown events. We fix this by filtering
out these overbroad events.

Also, don't do anything if the show/hide would be a no-op; this
also helps cut down on extraneous events.
2015-02-04 12:15:23 -06:00
Winston Chang
c930cce914 Check for unnamed arguments in ... 2015-02-03 15:55:24 -06:00
Winston Chang
424696cf96 Update NEWS 2015-02-03 10:11:34 -06:00
Joe Cheng
ea4ef45289 Merge pull request #715 from rstudio/bugfix/download-ext
downloadHandler temp files should have same extension as final download
2015-02-02 10:27:07 -08:00
Winston Chang
d2e13e6ac6 Merge pull request #719 from aronatkins/typo_04_mpg
fix "formula" spelling in 04_mpg example
2015-02-02 09:47:19 -06:00
Aron Atkins
70ff6658eb fix spelling 2015-02-02 10:09:08 -05:00
Joe Cheng
3e1732b9c0 downloadHandler temp files should have same extension as final download file 2015-02-01 08:37:44 -08:00
Winston Chang
4eb18dc797 Update NEWS 2015-01-28 15:43:23 -06:00
Winston Chang
6e7adfadb0 Merge pull request #710 from rstudio/bugfix/fixedpanel-cursor
Fix fixedPanel default cursor handling
2015-01-28 14:00:07 -06:00
Winston Chang
a866224f7b Switch to modified ion.rangeSlider 2.0.3. Closes #711
This includes the stopPropagation change, and the Shiny skin.
2015-01-28 13:56:31 -06:00
Winston Chang
77c50d6880 Update shiny.min.js 2015-01-28 11:36:28 -06:00
Winston Chang
4290e2e7b0 Merge pull request #702 from wch/select-width
Allow control over selectize width
2015-01-28 11:17:06 -06:00
Winston Chang
4e8632de73 Better documentation of plotOutput height (#705) 2015-01-28 11:15:08 -06:00
Joe Cheng
2792fe82a3 Fix fixedPanel default cursor handling
Previous to this fix, calling fixedPanel without an
explicit cursor argument would cause an error due to
the vector of possible values being passed as the
actual cursor argument to absolutePanel.
2015-01-27 18:41:29 -08:00
Winston Chang
ab6df9f8a9 Remove unused width control in shiny.js 2015-01-26 22:31:31 -06:00
Winston Chang
425489c74b Control width for non-selectize select inputs 2015-01-26 22:31:30 -06:00
Winston Chang
9f04517801 htmlOutput: allow custom container function 2015-01-26 16:50:09 -06:00
Winston Chang
9954639096 Allow control over selectize width
Previously, you could set the width of a selectInput with a pixel value
like 500px, but it wouldn't respect percent widths like 100%. This
commit makes width control the wrapper container's width, so it will
respect percent values.
2015-01-26 15:35:02 -06:00
Winston Chang
cd78364c17 Merge pull request #698 from daattali/patch-1
parseQueryString returns a list, not a vector
2015-01-25 21:05:17 -06:00
Dean Attali
563b986591 parseQueryString returns a list, not a vector 2015-01-24 20:42:34 -08:00
Winston Chang
fe5552773d sliderInput: use width argument (#675) 2015-01-23 15:30:20 -06:00
Winston Chang
b7acaf9519 Convert donttest examples; check for interactive() instead 2015-01-22 13:21:23 -06:00
Winston Chang
deffc90531 Remove remaining RJSONIO references 2015-01-22 13:15:01 -06:00
Joe Cheng
f54a6e8513 Add IE=edge to X-UA-Compatible header 2015-01-22 10:52:27 -08:00
Winston Chang
ab4dc641af Make jsonlite::toJSON convert all objects
By default, toJSON won't convert objects with classes that aren't registered
explicitly. This caused errors when converting html_dependency objects.
Setting this option causes jsonlite to convert all objects, including
html_dependency objects.
2015-01-21 15:09:12 -06:00
Winston Chang
dfe725dd78 Bump version and update NEWS 2015-01-21 14:16:40 -06:00
Winston Chang
dbe1e24561 Merge pull request #606 from wch/feature/jsonlite
Switch from RJSONIO to jsonlite
2015-01-21 14:14:46 -06:00
Winston Chang
075557929a Switch from RJSONIO to jsonlite 2015-01-21 14:12:53 -06:00
Winston Chang
d994db9c74 Add other authors to DESCRIPTION 2015-01-20 15:19:54 -06:00
Winston Chang
c462c61ac9 Bump version to 0.11.0.9000 for development 2015-01-20 15:19:40 -06:00
Winston Chang
1ef9719059 Merge tag 'v/0/11'
Shiny 0.11 released to CRAN
2015-01-18 22:25:11 -06:00
Winston Chang
3df0e7899c Update cran-comments 2015-01-15 23:49:47 -08:00
Winston Chang
927972d889 More license updates 2015-01-15 23:34:58 -08:00
bhsu
00f409d21d explicit parameter check 2015-01-14 13:34:27 -05:00
bhsu
6aea95b486 fixed application exit
fixed on.exit behavior
2015-01-14 09:59:57 -05:00
bhsu
e4dd78b9a4 renamed to destDir and documentation
fixed typo
2015-01-14 09:59:38 -05:00
B. Hsu
d940d5a597 updated run-url.R
added ability for user to change destination file when using runUrl, runGist or runGitHub

added messages

added messages informing user of final destination of app files
2015-01-13 16:47:53 -05:00
Winston Chang
5f1ea21be1 Add cran-comments file 2015-01-12 12:04:26 -06:00
Winston Chang
278851224d Re-document with roxygen2 4.1.0 2015-01-12 12:02:24 -06:00
Winston Chang
0161bc5a4e Update LICENSE information 2015-01-12 12:02:24 -06:00
Winston Chang
9cf5168d3f Merge branch 'master' into v0.11-rc 2015-01-11 17:54:51 -06:00
Winston Chang
f066a4bdf4 Negative margin for checkboxes/radios only after label (#678) 2015-01-09 14:48:16 -06:00
Winston Chang
0009756ed9 Bump version to 0.11 2015-01-08 14:55:36 -06:00
Winston Chang
481e5437f1 Add CONTRIBUTING.md to .Rbuildignore 2015-01-08 14:55:10 -06:00
Winston Chang
238f54e011 Change name of shinyBootstrap2 package to shinybootstrap2 2015-01-08 14:55:00 -06:00
Winston Chang
180525f538 Merge pull request #685 from rstudio/bugfix/qt-radio-check
Suppress Bootstrap top margin around radios and checkboxes in Qt5
2015-01-08 13:47:56 -06:00
Jonathan McPherson
9a1958d19a restrict changes to Linux (Qt5 on Windows is unaffected) 2015-01-08 11:03:30 -08:00
Jonathan McPherson
e1469a1e44 suppress Bootstrap top margin around radios and checkboxes in Qt5 2015-01-08 10:49:16 -08:00
Winston Chang
85bde2b00d Fix reference to old shiny version number 2015-01-07 22:03:40 -06:00
Winston Chang
b20a15b4ed Fix label class for non-inline checkbox and radios 2015-01-07 21:06:37 -06:00
Yihui Xie
a67161f521 add a pointer to the DT package 2015-01-06 14:26:19 -06:00
Yihui Xie
8d621e87a0 should inherit params from textInput instead of passwordInput 2015-01-06 14:17:57 -06:00
Winston Chang
a560034614 Fix another URL 2015-01-06 13:21:57 -06:00
Winston Chang
b329c1f94c Fix URL 2015-01-06 11:33:07 -06:00
Winston Chang
06459c0f52 Remove duplicate text in reactive domain docs 2015-01-05 11:23:05 -06:00
Winston Chang
2655c2511d Fix docs for slider step size 2015-01-05 11:20:38 -06:00
Winston Chang
fa9fdb01b0 Add info about using shinyApp and runApp together 2015-01-02 11:47:51 -06:00
Winston Chang
4896948d38 Update NEWS 2015-01-02 11:40:36 -06:00
Winston Chang
133a37817e Fix class for radio buttons 2014-12-19 15:18:54 -06:00
Winston Chang
0cdee5ed7a Add staticdocs entry for passwordInput 2014-12-15 13:09:35 -06:00
Winston Chang
2c21989b47 Don't limit width of inline inputs. Fixes #675 2014-12-15 12:22:31 -06:00
Winston Chang
17f796847d Use correct class for inline checkbox/radio label 2014-12-15 12:22:31 -06:00
Joe Cheng
02578dbf3a Fix tabset input; event changed for bootstrap 3 2014-12-14 09:59:23 -08:00
Yihui Xie
9f86e84830 closes #668: emphasize that I() does not work for non-root level elements in the options list in renderDataTable() 2014-12-13 22:52:28 -06:00
Winston Chang
1ae65bb999 Fix URL 2014-12-12 22:35:00 -06:00
Winston Chang
ca72f5fa99 Update devtools install instructions 2014-12-12 17:01:42 -06:00
Winston Chang
bc9b537d84 Merge pull request #673 from wch/handler-domain
Make default reactive domain available in request handlers. Fixes #669
2014-12-12 14:03:24 -06:00
Winston Chang
d9336d0ba2 Make default reactive domain available in request handlers. Fixes #669 2014-12-12 10:19:25 -06:00
Joe Cheng
eb537eaa24 Merge pull request #672 from hadley/input-types
Add support for more html 5 input types
2014-12-11 22:23:05 -08:00
hadley
f1d814ba04 Implement passwordInput in the same style as textInput() 2014-12-11 16:21:34 -06:00
hadley
760d360e96 Listen for events on all html 5 text inputs types 2014-12-11 16:21:11 -06:00
Winston Chang
5431fa1405 Remove unused jslider css entries 2014-12-11 10:24:29 -06:00
Winston Chang
eb809e388b withProgress: check that session is a session object 2014-12-10 15:49:32 -06:00
Winston Chang
0205ad7a4f Fix appearance of download button 2014-12-10 11:01:11 -06:00
Winston Chang
9599b14aa8 Add note about tools in main README 2014-12-09 14:43:28 -06:00
Winston Chang
d72585e3d1 Make JSHint more lenient 2014-12-09 13:38:46 -06:00
Winston Chang
735a15d7c6 Merge tag 'v/0/10/2.2'
Shiny version 0.10.2.2

Conflicts:
	DESCRIPTION
2014-12-08 16:51:37 -06:00
Winston Chang
0984e6ed90 Clean up importBootstrap code 2014-12-08 16:37:39 -06:00
Winston Chang
6004a4250a README edits 2014-12-08 16:29:52 -06:00
Winston Chang
b39fcc75d0 Add minified shiny.js 2014-12-08 16:23:02 -06:00
Winston Chang
a401553c13 Re-minify datepicker 2014-12-08 15:56:19 -06:00
Winston Chang
a312abff31 Don't run shiny.js minification 2014-12-08 15:56:19 -06:00
Winston Chang
92c1722469 Simplify npm install instructions 2014-12-08 15:56:19 -06:00
Winston Chang
e48136d31e Add grunt watch task 2014-12-08 15:56:19 -06:00
Winston Chang
b9d6f6fd9c Update tools/README 2014-12-08 15:56:19 -06:00
Winston Chang
66c8dfe44d Add jshint task 2014-12-08 15:56:19 -06:00
Winston Chang
5910c936b9 Use grunt for minification of datepicker 2014-12-08 15:56:19 -06:00
Winston Chang
a2645061fe Add Gruntfile 2014-12-08 15:56:19 -06:00
Winston Chang
7b887d2fd5 Bump version 2014-12-08 11:34:52 -06:00
Winston Chang
8d2367ed82 Remove use of rstudio::viewer for R CMD check 2014-12-08 11:33:56 -06:00
Joe Cheng
075583f4be Use minified jquery 2014-12-08 09:17:04 -08:00
Winston Chang
ce86e0a54a Re-document 2014-12-08 10:10:17 -06:00
Winston Chang
9308f8ea69 Fix documentation typo 2014-12-08 10:10:09 -06:00
Winston Chang
cc8b425adc Update license information 2014-12-05 14:49:24 -06:00
Winston Chang
25cf7955c9 Bump version to 0.10.2.9006 2014-12-05 14:31:06 -06:00
Winston Chang
d393865efc Update Bootstrap link 2014-12-05 14:30:46 -06:00
Winston Chang
9d877320d8 Merge pull request #658 from wch/feature/ionslider
New sliders
2014-12-05 14:30:07 -06:00
Winston Chang
1f72bef393 Update license information for ion.rangeSlider 2014-12-05 14:28:21 -06:00
Winston Chang
99c1069229 Add instructions for installing old version 2014-12-05 10:33:40 -06:00
Winston Chang
28718429e3 Fix arrows for date inputs. Fixes #663
The date inputs used css classes like icon-arrow-right, which no longer works
with font-awesome 4.x. This change uses glyphicon arrows instead, which are
included with Bootstrap and therefore don't need a separate HTML dependency.
2014-12-02 09:53:11 -06:00
Winston Chang
e145021760 Update to ion.rangeSlider 2.0.2 (with shiny mods) 2014-12-02 09:21:47 -06:00
Winston Chang
b7dd51c594 Fix case of directory 2014-12-02 09:08:29 -06:00
Winston Chang
9ebc3e5eec Fix file input appearance for Bootstrap 3 2014-11-26 19:34:27 -06:00
Winston Chang
4db60d7b27 Merge pull request #655 from wch/showcase-dep
Dynamically get font-awesome dependency from showcase body
2014-11-26 16:57:25 -06:00
Winston Chang
5d85199ae3 Dynamically get font-awesome dependency from showcase body 2014-11-26 16:54:27 -06:00
Winston Chang
088c9e5450 Better help for reactiveValues. Fixes #620 2014-11-26 15:28:16 -06:00
Winston Chang
bd51d1b2a2 Update NEWS 2014-11-26 14:20:25 -06:00
Winston Chang
0de7b6f63a Remove web resources for jslider 2014-11-26 14:20:25 -06:00
Winston Chang
85706eac84 Re-document 2014-11-26 14:20:25 -06:00
Winston Chang
96b646b94a Rename slider2Input to replace sliderInput 2014-11-26 14:20:25 -06:00
Winston Chang
753f6fc671 Update heuristic for step size 2014-11-26 14:19:06 -06:00
Winston Chang
3f186747ed Add keyboard support for sliders 2014-11-26 14:19:06 -06:00
Winston Chang
e6748c0793 Re-document 2014-11-26 14:19:06 -06:00
Winston Chang
2383796c49 Add slider2Input documentation 2014-11-26 14:19:06 -06:00
Winston Chang
fb38ab4ef2 Improve tick and step heuristics 2014-11-26 14:19:06 -06:00
Winston Chang
1242a62bca Set HTML data values to "true" and "false" 2014-11-26 14:19:06 -06:00
Winston Chang
55ceb12277 Simplify label code for slider2Input 2014-11-26 14:19:05 -06:00
Winston Chang
6dd4e7676d Add deprecation message for format argument 2014-11-26 14:19:05 -06:00
Winston Chang
4abb58b239 Add format options to sliders 2014-11-26 14:19:05 -06:00
Winston Chang
385dab6036 Add script for updating ion.rangeSlider 2014-11-26 14:19:05 -06:00
Winston Chang
2e9291decf Add QT-webkit touch detection workaround
This is from commit 813939b of ion.rangeSlider
2014-11-26 14:19:05 -06:00
Winston Chang
623036f03b Add updateSlider2Input 2014-11-26 14:19:05 -06:00
Winston Chang
98075e9d9d Add animation to ionsliders 2014-11-26 14:19:05 -06:00
Winston Chang
b80ce0e222 Add customized ionslider skin for Shiny 2014-11-26 14:19:05 -06:00
Winston Chang
b0162efb1f Add slider2Input 2014-11-26 14:19:05 -06:00
Winston Chang
7b3e9ab031 Limit width of inputs 2014-11-26 14:16:40 -06:00
Winston Chang
b35e866d95 Fix appearance of DataTables examples 2014-11-26 12:49:59 -06:00
Winston Chang
2d273d1550 Merge pull request #646 from yihui/feature/DT-1.10.3
upgrade to DataTables 1.10.4 and use Bootstrap 3
2014-11-26 12:44:39 -06:00
Yihui Xie
6aef3eb879 update the version info of DataTables 2014-11-26 10:15:18 -06:00
Winston Chang
61b0393657 Update tests for new select input structure 2014-11-26 10:09:27 -06:00
Winston Chang
30bf6c0714 Wrap select inputs in div 2014-11-26 09:51:22 -06:00
Winston Chang
fc64b115d3 Fix DOM structure for selectize inputs 2014-11-26 09:42:00 -06:00
Yihui Xie
bdc3f24ca6 the css of the processing indicator seems to be okay with Bootstrap 3 now 2014-11-26 00:13:39 -06:00
Joe Cheng
b28300b184 Merge pull request #660 from wch/body-tag
Allow running apps that have a body tag
2014-11-25 11:49:29 -08:00
Winston Chang
5c1f9d03e4 Update version and NEWS 2014-11-25 13:46:22 -06:00
Winston Chang
ed368a225d Refactor showcase ui code to handle body tags 2014-11-25 13:46:22 -06:00
Winston Chang
2f17f392d5 If UI has body tag, don't wrap in another body 2014-11-25 13:46:21 -06:00
Yihui Xie
b00a6e526e Bootstrap 3 for DataTables 2014-11-25 00:01:13 -06:00
Yihui Xie
75031df45b upgrade to DataTables 1.10.4
need the bugfix DataTables/DataTables#391
2014-11-25 00:00:55 -06:00
Winston Chang
39148a99d0 Make sure progress bars draw above other Bootstrap components 2014-11-24 13:52:08 -06:00
Winston Chang
d72f5ee2ad Better examples and docs for renderTable and renderDataTable 2014-11-24 11:24:26 -06:00
Winston Chang
c6ea459a68 Bump version to 0.10.2.9004 2014-11-21 08:26:05 -06:00
Joe Cheng
e8525e5513 Merge pull request #611 from rstudio/feature/bootstrap3
Switch to Bootstrap 3
2014-11-20 14:38:09 -08:00
Winston Chang
9046b85ca4 Fix appearance of date ranges 2014-11-20 14:50:18 -06:00
Winston Chang
19257b76d2 Fix spacing of checkbox input 2014-11-20 14:27:06 -06:00
Winston Chang
fd8990b294 Fix appearance of labels for checkbox group and radio buttons 2014-11-20 13:55:53 -06:00
Winston Chang
eb34f5e058 Don't limit text/number/select input width 2014-11-20 13:48:19 -06:00
Winston Chang
f8ced7e065 Merge pull request #656 from andeek/master
fixed iconClass function
2014-11-20 13:15:17 -06:00
Winston Chang
bf0a2d3c6c Fixes for progress bars with Bootstrap 3 2014-11-18 21:26:39 -06:00
Winston Chang
f5878326f7 Add CONTRIBUTING file 2014-11-18 10:50:48 -06:00
Winston Chang
1f0b439168 Add meta viewport tag 2014-11-17 16:13:55 -06:00
Winston Chang
3464e11152 Modify HTML5 shims so they are handled by htmlDependency
This adds conditional JS code so that the shim code isn't actually run
in browsers other than IE 8.
2014-11-17 16:13:55 -06:00
Winston Chang
b5f99be635 Add HTML5 shims for Bootstrap 3 to work with IE8 2014-11-17 14:43:35 -06:00
Winston Chang
3153b35c2a icon: add support for glyphicon library 2014-11-17 14:43:35 -06:00
Winston Chang
c450f9abc2 Re-document 2014-11-17 14:43:35 -06:00
Winston Chang
912434b259 Update navlistPanel for Bootstrap 3 2014-11-17 14:43:35 -06:00
Winston Chang
5f61fc658a actionButton: add btn-default class, for Bootstrap 3 2014-11-17 14:43:35 -06:00
Winston Chang
a268b74636 Update navbarPage for Bootstrap 3 2014-11-17 14:43:34 -06:00
Winston Chang
82a1bf7afd Deprecate 'collapsable' in favor of 'collapsible' 2014-11-17 14:43:34 -06:00
Winston Chang
4392676667 Add Bootstrap 3 note to README 2014-11-17 14:43:34 -06:00
Winston Chang
c47ec2c3c0 Register callbacks for each Bootstrap 3 class 2014-11-17 14:43:34 -06:00
Winston Chang
e756fc8daa Update NEWS 2014-11-17 14:43:34 -06:00
Winston Chang
4629262a1a Re-document 2014-11-17 14:43:34 -06:00
Winston Chang
741aec198b Fix inline checkboxGroupInputs and radioButtons 2014-11-17 14:43:34 -06:00
Winston Chang
c3e5b4fa36 Set width of divs inside of flowLayout 2014-11-17 14:43:34 -06:00
Winston Chang
d022907bcd Update showcase CSS classes for Bootstrap 3 2014-11-17 14:43:34 -06:00
Winston Chang
8a7603a45c Update slider animation buttons for Bootstrap 3 2014-11-17 14:43:34 -06:00
Winston Chang
2ade82d883 Fix headerPanel spacing
The titlepanel spacing also is unnecessary now with Bootstrap 3.
2014-11-17 14:43:34 -06:00
Winston Chang
3d8c38b558 Reduce spacing above sliders 2014-11-17 14:43:34 -06:00
Winston Chang
0f2d0a33b4 Adjust CSS for slider and selectize
This makes sliders and selectize inputs have width 100%, just like other
inputs with Bootstrap 3.
2014-11-17 14:43:34 -06:00
Winston Chang
d4ce1499cc Wrap inputs in div with class 'form-group' to maintain bottom margin 2014-11-17 14:43:33 -06:00
Winston Chang
9ab7895772 Fix appearance of date inputs 2014-11-17 14:43:33 -06:00
Winston Chang
ee9f79e287 Update selectize's CSS to use Bootstrap 3 2014-11-17 14:43:33 -06:00
Winston Chang
ad61dafb9a Correctly find checkboxes and radio buttons with Bootstrap 3 2014-11-17 14:43:33 -06:00
Winston Chang
b81361ff6d Update tests for new DOM structure of choices 2014-11-17 14:43:33 -06:00
Winston Chang
52417c0a60 Fix appearance of inputs 2014-11-17 14:43:33 -06:00
Winston Chang
000beeb737 Update tab shown/hidden events for Bootstrap 3 2014-11-17 14:43:33 -06:00
Winston Chang
7cce94000b Switch from Bootstrap 2 to 3 2014-11-17 14:43:33 -06:00
Andee Kaplan
7a4bdb4191 fixed iconClass function 2014-11-17 14:08:04 -06:00
Winston Chang
279a8ff989 Make font-awesome a dependency for icon() 2014-11-13 15:04:30 -06:00
Winston Chang
ed06a05ff0 Update font-awesome to 4.2.0 2014-11-13 14:06:45 -06:00
Joe Cheng
a56ac24cc2 Merge pull request #653 from yihui/bugfix/DT-encoding
encode the JSON response for DataTables/selectize with UTF-8
2014-11-13 09:03:42 -08:00
Yihui Xie
c8efd31d08 encode the JSON response for DataTables/selectize with UTF-8
to make sure multibyte characters in DataTables/selectize work
2014-11-13 10:27:56 -06:00
Winston Chang
d8875151e8 Un-normalize Progress values
This fixes an issue where Progress objects with a min and max other than
0 and 1 would not display properly.
2014-11-12 22:15:24 -06:00
Winston Chang
6082431161 Fixes for jshint 2014-11-03 15:26:59 -06:00
Joe Cheng
846c23a5a2 Merge remote-tracking branch 'origin/feature/event-reactives'
Conflicts:
	inst/tests/test-reactivity.r
2014-10-30 14:52:39 -07:00
Joe Cheng
9a5faa92c4 Refactor for code review feedback 2014-10-30 14:50:30 -07:00
Winston Chang
f149be26ce Add shiny-options to staticdocs index 2014-10-30 11:37:31 -05:00
Yihui Xie
c6d6ca5a5c bump version 2014-10-29 12:34:35 -05:00
Joe Cheng
98dc8069e3 Merge pull request #627 from yihui/bugfix/DT-XSS
escape HTML entities to avoid XSS attacks in DataTables
2014-10-29 10:29:21 -07:00
Winston Chang
32f5d68e51 Merge pull request #638 from wch/option-docs
Add documentation for global options
2014-10-29 11:31:09 -05:00
Winston Chang
855347a5d3 Add documentation for global options 2014-10-29 11:30:28 -05:00
Yihui Xie
78c22cb74a a news item for #630 2014-10-28 16:17:05 -05:00
Yihui Xie
8626a3efea make escape support column names in renderDataTable(), per suggestion of @jcheng5 2014-10-28 16:11:06 -05:00
Yihui Xie
d7e0d64ac2 fix the issue reported by Tareef: dplyr tbl_df objects are also data frames, but the default non-standard evaluation df[, j] will fail in dataTablesJSON(), so we need to coerce such objects to data frames explicitly 2014-10-28 16:11:06 -05:00
Yihui Xie
e26b1e54c8 a news item for #627 [ci skip] 2014-10-28 16:11:06 -05:00
Yihui Xie
594024472d apply escape to column names as well 2014-10-28 16:11:06 -05:00
Yihui Xie
5f60d09d0b per-column escaping 2014-10-28 16:11:06 -05:00
Yihui Xie
a05abda25c escape HTML entities to avoid XSS attacks in DataTables
BTW, per recommendation of http://datatables.net/manual/server-side, the parameter `draw` is coerced to integer
2014-10-28 16:11:06 -05:00
Winston Chang
daa8e44180 Update NEWS 2014-10-28 15:52:13 -05:00
Winston Chang
837a26daee Bump version to 0.10.2.9002 2014-10-28 15:48:47 -05:00
Joe Cheng
1223d3a2b3 Merge pull request #604 from rstudio/bugfix/observer-errors
Better handling of observer errors
2014-10-28 13:12:13 -07:00
Joe Cheng
a4d7eaf709 Merge pull request #630 from yihui/feature/httpuv-encode
use encodeURI[Component]() and decodeURIComponent() from httpuv
2014-10-28 13:08:04 -07:00
Yihui Xie
4b12d5527b increase version requirement of httpuv 2014-10-28 14:13:09 -05:00
Joe Cheng
e7553d6f15 Add observeEvent and eventReactive functions 2014-10-23 12:03:45 -07:00
Yihui Xie
b795d7de4e use encodeURI[Component]() and decodeURIComponent() from httpuv 2014-10-20 18:15:25 -05:00
Joe Cheng
e732afd64c Merge remote-tracking branch 'origin/feature/bootstrap-navbar-pos' 2014-10-20 13:16:42 -07:00
Winston Chang
40b25e3826 Merge pull request #597 from rstudio/selectize-0.11.0
Update to selectize 0.11.0
2014-10-20 15:13:13 -05:00
Winston Chang
b4d80b467a Merge pull request #610 from yihui/bugfix/DT-POST
fixes #605: send DT requests via POST instead of the default GET
2014-10-20 15:11:59 -05:00
Joe Cheng
62ef377dd1 Remove eventFilter for now
After discussing with @trestletech, the semantics are just not right.
When using it with a renderXXX function, it doesn't actually stop
recomputation, so the only reasonable place to use it is in a reactive
expression, but if that's true then this is a terrible looking API.
Will replace soon with something better.
2014-10-14 12:36:03 -07:00
Joe Cheng
b85b1e95b4 Fix documentation bug in ?validate 2014-10-14 12:30:11 -07:00
Joe Cheng
f2ab7001d2 Fix eventFilter logic 2014-10-14 10:10:08 -07:00
Joe Cheng
7fa6a2e9ef Fix action button 2014-10-14 09:25:52 -07:00
Joe Cheng
c499bbaa9f Update NEWS, bump version 2014-10-13 14:28:44 -07:00
Joe Cheng
f2b16c414f Merge remote-tracking branch 'origin/pr/180'
Conflicts:
	NAMESPACE
	R/bootstrap.R
	R/reactives.R
	R/shiny.R
2014-10-13 14:24:44 -07:00
Winston Chang
2a73e28b19 Merge pull request #615 from seanchrismurphy/patch-1
Update shiny.R
2014-10-12 09:21:58 -05:00
Sean Murphy
9252d1290c Update shiny.R
Update link to shiny tutorial (http://shiny.rstudio.com/tutorial/)
2014-10-12 22:16:28 +10:00
Yihui Xie
049bd85b29 fixes #605: send DT requests via POST instead of the default GET 2014-10-07 17:17:48 -05:00
Winston Chang
f95a0fa1d3 Update NEWS 2014-10-07 09:45:27 -05:00
Winston Chang
416466a0e1 Bump version to 0.10.2.9000 2014-10-07 09:44:19 -05:00
Winston Chang
bfd97c5484 Remove explicit dependency install for travis 2014-10-06 13:15:16 -05:00
Winston Chang
9c1badd6aa Fix test to avoid printing message
The recent release of testthat now displays messages in test blocks, which revealed that
this test needed to be updated.
2014-10-06 12:33:09 -05:00
Winston Chang
929cb29c5b Add global option for error handler function 2014-10-06 12:26:03 -05:00
Winston Chang
1e788962ef Merge pull request #607 from saurfang/patch-1
Use ... in actionButton and actionLink
2014-10-06 11:51:52 -05:00
saurfang
26f8c11526 Add ... to actionButton and actionLink 2014-10-04 13:00:29 -04:00
Winston Chang
a9b3922061 Remove unused withCallingHandlers() 2014-10-03 16:19:03 -05:00
Winston Chang
00ebe4fab2 Add test for observer error handling 2014-10-03 16:17:49 -05:00
Joe Cheng
1bee6aece7 Better handling of observer errors
- Unhandled observer error no longer stops flushReact in mid-flush
- Observer errors are now warnings that include the observer label
- Session is explicitly being closed by Shiny instead of by httpuv

Also:
- session$close() is now public and closes the session
2014-10-02 11:13:23 -07:00
Winston Chang
be4eff413d Bump version to 0.10.2.1 2014-10-01 10:44:44 -05:00
Winston Chang
e56571840b Change some examples to donttest, to make CRAN happy 2014-10-01 10:32:10 -05:00
Winston Chang
f931222256 Update NEWS 2014-09-29 15:21:43 -05:00
Winston Chang
25ff7d430d Bump selectize version in html dependencies 2014-09-29 15:21:43 -05:00
Winston Chang
d9cf3ceb9b Update to Selectize 0.11.2 with computedstyle fix
Fixes #596
2014-09-29 15:21:43 -05:00
Winston Chang
c37a84ab4d Bump version to 0.10.2 2014-09-29 12:18:36 -05:00
Winston Chang
cf97fc9b95 Merge pull request #598 from yihui/feature/ie8-uploads
IE8/9 file upload
2014-09-29 10:15:06 -05:00
Yihui Xie
03a8651cfd use typeof(x) === 'undefined' instead of x === undefined 2014-09-26 16:57:57 -05:00
Yihui Xie
b206525f8e add a news item for file uploading in IE8/9 2014-09-25 18:07:58 -05:00
Yihui Xie
443850b778 fileInput() works for IE8/9 now, but they do not support multiple files 2014-09-25 18:04:50 -05:00
Yihui Xie
6962fbf6f7 do not store the FileUploader in el.data('currentUploader') for IE (it does not have the .abort() method) 2014-09-25 17:47:41 -05:00
Yihui Xie
a2a7173e30 use the IE8 file uploader only for IE 2014-09-25 17:17:28 -05:00
Yihui Xie
698ad2b890 I do not see why this needs to be changed 2014-09-25 17:07:22 -05:00
Yihui Xie
dd43a82042 IE8 does not support iframe.onload; we need to use .attachEvent() instead 2014-09-25 17:02:08 -05:00
Yihui Xie
a25515dc2b install mime for travis ci 2014-09-25 14:51:41 -05:00
Yihui Xie
e1a8e119bf Add import for mime 2014-09-25 14:51:34 -05:00
Joe Cheng
4712b72019 Force IE8 uploads to kick off reactive flush 2014-09-25 14:28:42 -05:00
Yihui Xie
2d162b0d4e parse the multipart form data POSTed and save the file info in .input 2014-09-25 14:28:42 -05:00
Yihui Xie
1ea4b4d0b5 the iframe does not need src, and we should attach the onload event after it is appended to body, otherwise it will be destroyed immediately 2014-09-25 14:28:42 -05:00
Yihui Xie
c75c7019a8 the key problem with the form submission was that the name was missing 2014-09-25 14:28:42 -05:00
Yihui Xie
67ab5fbc8a return a valid response temporarily 2014-09-25 14:28:42 -05:00
Yihui Xie
31a5bee228 if evt.target.files is undefined, it is probably IE8; we will use iframe from POST to upload the files later 2014-09-25 14:28:42 -05:00
Yihui Xie
bcd7195bf5 use uploadie instead of upload2 because of regexec("^/([a-z]+)/([^?]*)" earlier ([a-z]+ won't match upload2) 2014-09-25 14:28:42 -05:00
Yihui Xie
322a9d397a config.sessionId is in this.shinyapp instead of this 2014-09-25 14:28:42 -05:00
Yihui Xie
71e6646ea0 use encodeURI() instead of the deprecated escape() 2014-09-25 14:28:42 -05:00
Joe Cheng
b505507c35 file upload via <iframe> for IE8 2014-09-25 14:28:42 -05:00
Winston Chang
76535c1da5 Add missing entries to staticdocs index 2014-09-24 11:21:29 -05:00
Winston Chang
9edd94e1c0 Fix incomplete sentence 2014-09-16 13:59:48 -05:00
Winston Chang
32449b3c55 Re-document with roxygen2 4.0.2 2014-09-16 13:55:16 -05:00
Winston Chang
76c3d38e11 Add inc method to Progress 2014-09-16 13:54:17 -05:00
Winston Chang
0e8ed7d770 Refactor Progress to have private members 2014-09-11 14:22:01 -05:00
Winston Chang
5af4743f2f withProgress: evaluate expression in calling env, not in a child 2014-09-11 13:30:58 -05:00
Joe Cheng
ab86232294 Add position parameter to navbarPage 2014-09-10 22:59:35 -07:00
JJ Allaire
0202daf551 bump version 2014-09-10 14:28:29 -04:00
Winston Chang
3b062de156 Update travis config: htmltools 0.2.6 is on CRAN 2014-09-08 13:49:11 -05:00
Joe Cheng
65786c4d41 Fix off-by-one error in dependency attachments 2014-09-05 14:57:49 -07:00
Yihui Xie
d3bb742308 Merge pull request #586 from trestletech/doc/serverInfo
Added a clarifying comment to serverInfo.
2014-09-04 17:14:41 -05:00
trestletech
f98aa3f12b Added a clarifying comment to serverInfo. 2014-09-04 16:30:35 -05:00
Winston Chang
70881bb367 Update NEWS 2014-09-04 15:54:48 -05:00
Winston Chang
50adb5fdf5 sliderInput: Round using min value as baseline. Fixes #301
This uses jslider commit da06841.
2014-09-04 15:00:19 -05:00
Winston Chang
c05701fc19 sliderInput: fix rounding bug. Fixes #502
This uses jslider from commit 22cd17e
2014-09-04 14:37:11 -05:00
Yihui Xie
5e68b5f3e3 bump version 2014-09-03 17:22:35 -05:00
Yihui Xie
5f46d97409 fixes #306: should use file_test('-d') to check if a directory exists, instead of file.exists(), because file.exists('foo/') is FALSE even if the directory foo exists
I was bitten by this once before: a874ac5b66
2014-09-03 17:21:50 -05:00
Yihui Xie
7f07e47488 update URL in DESCRIPTION 2014-09-03 17:21:50 -05:00
Jeff Allen
3999f4d3a5 Updated external links to the Shiny Dev Center. 2014-09-03 11:18:24 -05:00
Yihui Xie
b3d6220b01 fixes #581: check for undefined instead of null 2014-08-29 15:31:10 -05:00
Winston Chang
7d88775b5a Faster Map implementation 2014-08-28 23:12:09 -05:00
Winston Chang
2ca5d3e0df Restore class attribute for Map
This is because there are S3 methods for Map.
2014-08-28 23:07:46 -05:00
Winston Chang
3f34030a12 Cleaner method of getting execCount 2014-08-28 20:21:45 -05:00
Winston Chang
11dfa3d9aa Remove unneeded @.Data field 2014-08-28 20:21:45 -05:00
Winston Chang
6923a11038 Don't add class attribute for internal-facing classes
The class attribute is unneded for these classes, and this improves
performance.
2014-08-28 20:21:05 -05:00
Winston Chang
33d78fcf29 Update NEWS 2014-08-28 19:44:43 -05:00
Winston Chang
2b3cfdf18b Migrate reactlog to use Stack 2014-08-28 19:20:10 -05:00
Winston Chang
aa7a3f7013 Reverse order of Stack as_list() 2014-08-28 19:14:15 -05:00
Winston Chang
1e1b3c8f5f Faster stack implementation 2014-08-28 17:31:53 -05:00
Yihui Xie
a7cac36974 bump version 2014-08-28 16:58:36 -05:00
Yihui Xie
3af800e522 add the R version requirement to NEWS 2014-08-28 16:57:06 -05:00
Yihui Xie
cf135dd658 Revert "Revert "Remove caTools dependency""
This reverts commit 8d4b9076f7.

The main concern for the previous reversion was the Glimmer/Spark servers (Rcpp requires R >= 3.0.0). We are able to install Rcpp/httpuv under R 2.15.3 (https://gist.github.com/yihui/43a68d811dade1d9e828), so it is possible to upgrade Rcpp/httpuv/shiny on Glimmer/Spark. On the other hand, we are going to shut down Glimmer/Spark by the end of this year anyway, and move to ShinyApps.io, which makes this R 3.x issue even less of concern.
2014-08-28 16:55:03 -05:00
Winston Chang
4e9d113896 Bump version to 0.10.1.9005 2014-08-28 16:31:30 -05:00
Winston Chang
af8e81d208 Update NEWS 2014-08-28 16:31:22 -05:00
Winston Chang
83fa1ea4a6 Merge pull request #580 from wch/r6class
Migrate from reference classes to R6
2014-08-28 16:21:39 -05:00
Winston Chang
a72f8b7b65 Merge pull request #579 from yihui/feature/DT-caseInsensitive
Case insensitive searching in DataTables
2014-08-28 16:21:16 -05:00
Winston Chang
1b940a3117 Install R6 for travis 2014-08-28 16:02:40 -05:00
Winston Chang
5012831e7b Add tests for nested query strings 2014-08-28 15:59:50 -05:00
Winston Chang
85fb08e9a5 Update tests for R6 2014-08-28 15:45:56 -05:00
Winston Chang
7ac84b6a91 Switch from refclasses to R6 2014-08-28 15:45:44 -05:00
Yihui Xie
3a72526016 update news to reflect changes in DataTables 2014-08-28 15:38:55 -05:00
Yihui Xie
c3e78f41b0 implement case-[in]sensitive searching on the server side (#400)
grep2() was invented to deal with these situations:

1. case-insensitive and fixed matching
2. when the regex is incomplete
2014-08-28 15:38:47 -05:00
Yihui Xie
fdea9dddee send search.caseInsensitive to the server to make it possible to do case-insensitve searching 2014-08-28 15:30:43 -05:00
Winston Chang
2d3dd7d91d Field type should be a string 2014-08-27 14:09:39 -05:00
Winston Chang
2487245e94 Replace == with === 2014-08-26 13:23:38 -05:00
Joe Cheng
a4f12691ce Use encodeURI instead of escape 2014-08-26 09:41:00 -07:00
Winston Chang
e7e83eb8bb Merge pull request #576 from yihui/bugfix/DT-searchbox
escape the placeholders of search boxes in DataTables, and strip the HTML tags off
2014-08-26 11:02:14 -05:00
Yihui Xie
e8ffb68c08 escape the placeholders of search boxes in DataTables, and strip the HTML tags off 2014-08-25 16:45:00 -05:00
Yihui Xie
283f69cb65 use the latest version of htmltools 2014-08-22 12:16:45 -05:00
Winston Chang
0fb4ab2dcf Merge pull request #558 from yihui/feature/datatables1.10
DataTables 1.10.2
2014-08-22 12:02:39 -05:00
Yihui Xie
063ac989be closes yihui/shiny#4 after cleaning it up a bit
use [searchField] instead of $.makeArray(), and unlist() it on the R side
2014-08-22 00:11:00 -05:00
Xin Yin
82fb11a7b5 Adopted Yihui's suggestion to use $.makeArray() to fix a bug with searchField option in selectizeInput(), caused by RJSONIO:::fromJSON() 2014-08-21 23:58:50 -05:00
Yihui Xie
d238d61906 need a newer version of htmltools due to 5f4c8cf176 and the bug rstudio/htmltools#7 2014-08-21 15:28:53 -05:00
Yihui Xie
22fdc90159 add instructions for upgrading from DataTables 1.9 to 1.10 2014-08-21 14:24:39 -05:00
Yihui Xie
b6cf4c4375 background color for selected rows 2014-08-21 12:12:34 -05:00
Yihui Xie
8aa32fff34 get rid of the ugly trick eval(parse()), and use a plain loop to create a nested list 2014-08-21 12:10:26 -05:00
Yihui Xie
76d6ffea4a tweak doc and roxygenize 2014-08-21 12:10:26 -05:00
Yihui Xie
ea8ca8ea1e new option names for DataTables from Hungarian to camelCase notations 2014-08-21 12:10:26 -05:00
Yihui Xie
ed9ca04c58 support [] in query strings like $_GET in PHP, because server-side DataTables 1.10 passes parameters as arrays
e.g. columns[0][search][value]=foo&columns[1][search][value]=bar

we need list(columns = list(`0` = list(search = list(value = 'foo')), `1` = ...)
2014-08-21 12:10:26 -05:00
Yihui Xie
093fbaa178 the names of keys and values are useless 2014-08-21 12:10:26 -05:00
Yihui Xie
5f4c8cf176 tweaking the bootstrap style copied from DataTables:
1. sorted columns have different colors;
2. correct position of the processing info;
3. override the width of text input (search fields), otherwise they will be too wide (206px defined in bootstrap.min.css);
2014-08-21 12:10:06 -05:00
Yihui Xie
c7ee37804c fix a bug when the number of rows of data to show is zero
all(logical(0)) == TRUE!
2014-08-21 11:35:37 -05:00
Yihui Xie
e0c31aa5af upgrade DataTables from 1.9.4 to 0.10.2; closes #487 2014-08-21 11:35:37 -05:00
Yihui Xie
ab1494777d fixes #573: use the new MathJax CDN 2014-08-20 16:40:00 -05:00
Winston Chang
c01fafb605 Bump version to 0.10.1.9004 2014-08-20 11:49:47 -05:00
Winston Chang
5be2ffc0b2 Update NEWS 2014-08-20 11:49:37 -05:00
Winston Chang
3ede9396da Merge branch 'progress'
Conflicts:
	NAMESPACE
2014-08-20 11:31:28 -05:00
Winston Chang
e400a7a15e Update progress documentation 2014-08-20 11:25:28 -05:00
Winston Chang
2939006a9a Merge pull request #571 from rstudio/feature/dependency-attachment
Add createWebDependency and renderDependencies functions
2014-08-20 09:48:44 -05:00
Winston Chang
df975a0b6b Add missing semicolon 2014-08-20 09:48:25 -05:00
Joe Cheng
bda86de632 Update metadata 2014-08-19 09:54:32 -07:00
Joe Cheng
5738a4ba48 Add createWebDependency and renderDependencies functions 2014-08-18 13:27:55 -07:00
Joe Cheng
38cfa46131 Roxygenize 2014-08-18 13:27:15 -07:00
Winston Chang
9525df1381 Add missing semicolon 2014-08-15 16:36:45 -05:00
Winston Chang
d393577ba8 uiHttpHandler: return NULL if no ui
This restores missing UI detection for single-file apps, which was lost
in 0f431ed.
2014-08-13 15:39:18 -05:00
Winston Chang
f7c2a07b70 Update NEWS 2014-08-13 15:32:08 -05:00
Winston Chang
adf69b4890 Look for server.R before app.R 2014-08-13 15:30:40 -05:00
Winston Chang
593d22b640 Bump version to 0.10.9002 2014-08-13 14:48:45 -05:00
Winston Chang
7706eebafb Remove single file example
The example will be moved to the gallery.
2014-08-13 14:22:26 -05:00
Joe Cheng
91bd5127fb Merge pull request #563 from rstudio/single-file2
Single-file app support
2014-08-12 19:24:58 -07:00
Winston Chang
b87a0d7f25 Automatically display app.R file in showcase mode 2014-08-12 16:47:41 -05:00
Winston Chang
0f431ed384 Detect showcase mode for single-file apps 2014-08-12 16:36:00 -05:00
Winston Chang
d520921b13 Merge pull request #564 from rstudio/feature/output-resize
Add support for resize(el, width, height) method on output bindings
2014-08-12 15:13:22 -05:00
Joe Cheng
8d4b9076f7 Revert "Remove caTools dependency"
This reverts commit e4239c924b.

I totally forgot the problems this causes with R 2.15 and thus
glimmer/spark. httpuv 1.2.2 requires Rcpp 0.11 which requires
R 3.0. So existing installs (like glimmer/spark) that are
running just fine with httpuv 1.2.0 will be forced to upgrade,
which is hard to do when you don't know the provenance of
all the packages installed by your users.
2014-08-12 10:24:33 -07:00
Joe Cheng
93ebbcaf04 Merge pull request #567 from rstudio/feature/remove-prefix-warning
remove addResourcePath warning for overriding an existing prefix
2014-08-09 12:45:14 -07:00
JJ Allaire
ecde1580fd remove addResourcePath warning for overriding an existing prefix 2014-08-09 06:39:27 -04:00
Joe Cheng
8f73bb222c Add support for resize(el, width, height) method on output bindings 2014-08-08 00:43:02 -04:00
Winston Chang
1108e04eff Update missing-UI web page to include app.R 2014-08-07 13:26:07 -05:00
Winston Chang
0f1a8f3358 Add single-file app example 2014-08-07 13:25:49 -05:00
Winston Chang
77de4df0ff shinyApp: use NULL default for ui and server
This is so that, when a single-file app returns a shinyApp with a blank
`ui` argument, Shiny will not error out, and instead it can search for
a www/ subdirectory.
2014-08-07 13:18:21 -05:00
Winston Chang
0564de37ee Add support for shinyAppDir with single-file app.R 2014-08-06 21:51:36 -05:00
Winston Chang
8c584ae0e0 Refactor file.path.ci, add find.file.ci and file.exists.ci 2014-08-06 21:19:46 -05:00
Winston Chang
30c80279c8 Remove accidental browser() 2014-08-06 21:18:45 -05:00
Winston Chang
3f0ab9a88a Fixes to file.path.ci
There were two bugs, which are fixed:
* It didn't find files starting with '.' because `all.files` defaults to FALSE.
* It was too loose with file matching - the `pattern` argument to list.files
  is a regexp, not string literal.
2014-08-06 12:19:08 -05:00
Winston Chang
6da3fcf446 Add container for all progress items 2014-08-04 16:01:47 -05:00
Winston Chang
26746ca303 Don't use multiline string in JS 2014-08-01 21:11:44 -05:00
Winston Chang
64158eac43 Make progress position more customizable 2014-08-01 21:11:03 -05:00
Yihui Xie
9e3a7f5eda a typo in the news for 0.10.1 2014-08-01 17:16:47 -05:00
Yihui Xie
0a4f3db8ae bump version 2014-08-01 16:37:20 -05:00
Yihui Xie
c095085d84 fixes #557: choicesWithNames() turns a character vector to a list, which is no longer appropriate as a column in data.frame() 2014-08-01 16:37:20 -05:00
Yihui Xie
41cc4e68e3 no need to use wrap = FALSE for roxygen2 now 2014-08-01 16:37:20 -05:00
Winston Chang
21fb7959a5 Fix edge case with nested choices. Fixes #560
When the set of choices is a list containing a named vector of length 1,
choicesWithNames would return the wrong result.
2014-08-01 16:11:51 -05:00
Yihui Xie
3aa22127e0 a consequence of PR #552 is R 3.0.0
those who still wish to install shiny under R 2.15.x may take a look at these instructions: https://gist.github.com/yihui/43a68d811dade1d9e828
2014-08-01 15:28:43 -05:00
Winston Chang
a679a37ffa Make progressHandlers a simple object 2014-08-01 15:16:54 -05:00
Winston Chang
649857ec28 Update NAMESPACE 2014-07-30 14:15:42 -05:00
Winston Chang
4a6136b918 Fade in bars 2014-07-30 14:15:42 -05:00
Winston Chang
6e1c468a80 Simplify R API for progress 2014-07-30 14:15:42 -05:00
Winston Chang
cadcd0c5e8 Export Progress generator 2014-07-30 14:15:42 -05:00
Winston Chang
a531c306f1 Make progress bar show on top 2014-07-30 14:15:42 -05:00
Winston Chang
b0a9449335 Simplify argument handling 2014-07-30 14:15:42 -05:00
Winston Chang
b6deb87cae Unify binding and page-level progress interface 2014-07-30 14:15:41 -05:00
Winston Chang
7319c88674 Use new message format for progress reporting 2014-07-30 14:15:41 -05:00
Winston Chang
d36317c563 Add missing 'var' 2014-07-30 14:15:41 -05:00
Winston Chang
1917202bd0 Improve handling of closed progress 2014-07-30 14:15:41 -05:00
Winston Chang
a8338912e0 Simplify code 2014-07-30 14:15:41 -05:00
Winston Chang
bfea3201e8 Put progress stack in session object 2014-07-30 14:15:41 -05:00
Winston Chang
a9bb440e6c Add Stack ref class 2014-07-30 14:15:41 -05:00
Winston Chang
f0942d58e8 Get session without needing to pass it in 2014-07-30 14:15:40 -05:00
Winston Chang
aa093659a0 Copy over progress code from shinyIncubator 2014-07-30 14:15:40 -05:00
Winston Chang
cccdbc05a5 Bump to development version number 2014-07-27 22:22:22 -05:00
Winston Chang
dfa32b7be4 Merge tag 'v/0/10/1'
Shiny 0.10.1 released to CRAN
2014-07-27 22:19:44 -05:00
Winston Chang
c7e0bd037a Merge pull request #552 from rstudio/no-catools
Remove caTools dependency
2014-07-25 14:43:15 -05:00
Winston Chang
6c711b76b0 Bump version to 0.10.1 2014-07-25 14:20:43 -05:00
Winston Chang
9c914f10c4 Merge pull request #553 from wch/hidden-selectize
Add custom version of selectize.js to work around Firefox bug
2014-07-25 13:37:08 -05:00
Winston Chang
eda56d118a Merge pull request #549 from yihui/bugfix/utf8-bom
warn against the byte order mark if exists; fixes #545
2014-07-24 16:09:56 -05:00
Winston Chang
02c7351c6d Add custom version of selectize.js to work around Firefox bug
This is a workaround for issue #550. This version is based on selectize version 0.9.1.
2014-07-24 15:29:23 -05:00
Yihui Xie
ab618235f1 one more check before we use UTF-8: see if there are embedded nul's 2014-07-24 14:48:23 -05:00
Joe Cheng
e4239c924b Remove caTools dependency
Instead, use base64 encoding function from httpuv
2014-07-24 10:37:14 -07:00
Yihui Xie
ffead9ed70 add explanations of skipping *nix when checking encoding, and point to the shiny dev center article 2014-07-24 11:57:46 -05:00
Winston Chang
36aefadced Merge pull request #550 from rstudio/bugfix/offscreen-shinyapps
Deal gracefully with elements that have no computed style available
2014-07-23 11:55:24 -05:00
Jonathan McPherson
75ccfe38ce update comment with more specific browser notes 2014-07-23 09:43:42 -07:00
Jonathan McPherson
e3cb3fe2e4 deal gracefully with elements that have no computed style available 2014-07-22 14:41:34 -07:00
Yihui Xie
983e7e9b75 warn against the byte order mark if exists; fixes #545 2014-07-22 16:22:50 -05:00
Yihui Xie
3db47c076c a news item for the optgroup feature 2014-07-18 14:40:58 -05:00
Yihui Xie
eeff285b33 add links to examples in shiny dev center 2014-07-18 14:40:31 -05:00
Yihui Xie
029595f8ea an edge case selectInput(choices = NULL)
firstChoice() may fail with an error "subscript out of bounds"
2014-07-17 15:59:33 -05:00
Yihui Xie
ea2ec27724 bump version 2014-07-17 14:52:26 -05:00
Yihui Xie
f6bf4a416f Merge pull request #537 from yihui/bugfix/native-encoding
Use native encoding internally
2014-07-17 14:49:53 -05:00
Yihui Xie
af978a68e3 tweak the warning message
and simply stop() in case the user has set option(encoding = 'UTF-8')
2014-07-17 14:39:21 -05:00
Yihui Xie
89dc1323e1 add a note section about the clickId/hoverId arguments in plotOutput(), since they seem to have been confusing grid graphics users
and re-wrap the roxygen comments
2014-07-16 17:27:00 -05:00
Yihui Xie
a4b5f63deb a single quote ' was omitted here, making the Rd for plotOutput() incomplete since this line was ignored 2014-07-16 17:27:00 -05:00
Winston Chang
feaa6ccff4 Merge pull request #542 from rstudio/feature/select-optgroup
Feature/select optgroup (closes #520)
2014-07-16 17:22:29 -05:00
Winston Chang
7159293337 Use consistent indentation for function definitions 2014-07-16 17:04:22 -05:00
Winston Chang
4a5b31e3a7 Simplify needOptgroup function 2014-07-16 16:57:17 -05:00
Winston Chang
6f1dc89fb3 Enable union merge for NEWS 2014-07-16 16:48:56 -05:00
Yihui Xie
29dd405fe5 the options and ... arguments are no longer needed 2014-07-16 15:50:31 -05:00
Yihui Xie
0f0b0cd3d8 explicitly define updateSelectInput() instead of using the trick to change the options argument of updateInputOptions() 2014-07-16 15:50:08 -05:00
Winston Chang
262528e36a Add tests for deeper nesting with choicesWithNames 2014-07-16 12:07:13 -05:00
Winston Chang
597e86dd57 Make listify work on nested lists of depth > 1 2014-07-16 12:02:55 -05:00
Winston Chang
b604dba948 Add tests for default selected items 2014-07-16 00:52:29 -05:00
Winston Chang
1837a64bd2 Add tests for selectOptions 2014-07-16 00:51:57 -05:00
Winston Chang
9b413de4d8 selectOptions: handle mixed options and optgroups 2014-07-16 00:51:57 -05:00
Winston Chang
3d77cbd677 Slight clarification of comment 2014-07-16 00:51:57 -05:00
Winston Chang
62176c3218 Add tests for choicesWithNames 2014-07-16 00:51:57 -05:00
Winston Chang
d7a01c32cc Always convert choices to a (named) list
Converting it to a list, and ensuring that it's a named list reduces
many checks elsewhere.
2014-07-16 00:51:57 -05:00
Yihui Xie
cc493fd545 fall back to native encoding on Windows if UTF-8 does not work 2014-07-15 16:05:23 -05:00
Yihui Xie
6b8679454d factor out .Platform$OS.type == 'windows' as isWindows() 2014-07-15 16:04:02 -05:00
Yihui Xie
1b68d61e54 R CMD check will warn against the possibly missing variables inline and type 2014-07-11 17:36:37 -05:00
Yihui Xie
418de862e6 rename newOptions to config 2014-07-11 14:17:08 -05:00
Yihui Xie
413653858e inherit doc for updateFooInput() from fooInput() 2014-07-11 14:03:47 -05:00
Yihui Xie
f0886a7556 when we need <optgroup> for the child elements of choices, we just generate it no matter what the child element is
e.g. we use <optgroup> for A even if A only has one element: list(A = 'a', B = c('b1', 'b2'))
2014-07-11 14:03:47 -05:00
Yihui Xie
0e2666948f when choice is not a list, we need to return its first element 2014-07-11 14:03:47 -05:00
Yihui Xie
d2fc851816 make updateSelectInput(), updateCheckboxGroupInput(), and updateRadioButtons() work
now session$sendInputMessage() does not send options as the choices data, but as a pre-generated raw HTML string; in shiny.js, we just receive this string, and .append() it to the input after the input is emptied
2014-07-11 14:03:47 -05:00
Yihui Xie
e1fb29c8c5 factor out the code to generate options from checkboxGrouptInput() and radioButtons(), and use the new generator generateOptions() for them 2014-07-11 14:03:47 -05:00
Yihui Xie
fe3158fdd6 validateSelected() does not validate selected for the optgroup case; this function is only for shiny <= 0.9 2014-07-11 14:03:47 -05:00
Yihui Xie
721b26f80b choicesWithNames() should also consider the optgroup case now: all optgroup nodes must be named 2014-07-11 14:03:47 -05:00
Yihui Xie
d3ecfb22ee closes #326: generate <optgroup> when choices is a named list of choices
note the nested level of optgroup can be greater than one here, however, the HTML4 spec only allows one level, i.e. optgroup must have select as its direct parent http://stackoverflow.com/q/1037732/559676
2014-07-11 14:03:47 -05:00
Yihui Xie
27a98020c9 recursively select the first choice, to make sure selected is a scalar, even when choices is a list of lists (optgroup) 2014-07-11 14:03:47 -05:00
Yihui Xie
ab56b72f39 json2.js modified and uglified from https://github.com/yihui/JSON-js via http://lisperator.net/uglifyjs/
I'm using the date of json2 as its version number, since it does not really have a version number

This should close rstudio/shiny-server#79
2014-07-10 17:56:23 -05:00
Yihui Xie
8063f66958 let's read ui.R, server.R, README.md, and DESCRIPTION also with UTF-8
the reason for this is that htmltools::htmlEscape() uses gsub(..., x, fixed =
TRUE), which does not work on Windows if x is encoded in UTF-8; fixed = TRUE
only works with the native encoding
2014-07-10 15:59:42 -05:00
Yihui Xie
bf270b9adb convert the message to native encoding from UTF-8 before decoding it
on Windows, switch(input$foo, foo1 = val1) does not work even if input$foo ==
foo1 but Encoding(input$foo) is UTF-8 while foo1 is unknown (native encoding);
to prevent such problems, let's always use native encoding inside the shiny
process, and only do the UTF-8 conversion at I/O time

special thanks to @desar for the thorough tests
2014-07-10 15:59:42 -05:00
Joe Cheng
972db08740 Merge pull request #539 from yihui/doc/conditionalPanel
add a Note section to the documentation of conditionalPanel(), since it ...
2014-07-10 00:41:36 -07:00
Yihui Xie
6326c7cbaa add a Note section to the documentation of conditionalPanel(), since it always confuses R users
e.g. https://groups.google.com/d/msg/shiny-discuss/AFItYcRXzyw/ywRy3EEtjw4J
2014-07-10 00:11:11 -05:00
Yihui Xie
4152ace514 Merge pull request #538 from rstudio/bugfix/showcase-nullref
fix #500: check for null source ref highlight points
2014-07-09 11:55:02 -05:00
Jonathan McPherson
038221408c fix #500: check for null source ref highlight points 2014-07-09 09:26:39 -07:00
Joe Cheng
9f76def7ce Merge pull request #533 from rstudio/bugfix/slow-options
Calling getOption() with default is slow
2014-07-06 16:38:25 -07:00
Joe Cheng
1b83770c5c Merge pull request #528 from yihui/bugfix/showcase-encoding
use UTF-8 for showcase mode, and assume DESCRIPTION is also UTF-8
2014-07-06 12:13:05 -07:00
Joe Cheng
3458d924ca Calling getOption() with default is slow
This has a measurable effect in apps with lots of reactives.

Reported by Aran Lunzer
2014-07-06 12:10:51 -07:00
Yihui Xie
0749b9500c use UTF-8 for showcase mode, and assume DESCRIPTION is also UTF-8
this time we should fix #136 now; I did not find other files that have to be
read with UTF-8
2014-06-26 15:41:12 -05:00
Jonathan
b1dfc18a8c Merge pull request #527 from rstudio/render-rmd-warning
Emit R Markdown warnings for render* functions as well as shinyApps
2014-06-25 11:18:41 -07:00
Jonathan McPherson
7b25c282c0 append rather than replace knit_meta with Shiny warning 2014-06-25 10:20:07 -07:00
Yihui Xie
a128ceaf2d bump version 2014-06-25 10:41:34 -05:00
Jonathan McPherson
f266cab580 emit R Markdown warnings for render* functions as well as shinyApps 2014-06-24 16:43:58 -07:00
Yihui Xie
23bf9aaf17 Merge pull request #526 from rstudio/bugfix/plot-captures-output
Revert "tweak after #492: capture.output() does withVisible() and print(...
2014-06-24 13:40:45 -05:00
Joe Cheng
1983f60ec6 Revert "tweak after #492: capture.output() does withVisible() and print() if necessary"
This reverts commit 451f950d0d.

Too-aggressive capture.output was causing browser() not to work in
renderPlot().
2014-06-24 06:09:36 -07:00
Yihui Xie
27f8909406 bump version 2014-06-19 13:50:39 -05:00
Yihui Xie
9988206911 add news for #512 2014-06-19 13:50:06 -05:00
Joe Cheng
31fe1fdfa6 Merge pull request #523 from rstudio/feature/navbarPage-windowTitle
Add windowTitle parameter to navbarPage
2014-06-19 10:45:01 -07:00
Joe Cheng
77b125ce2d Add windowTitle parameter to navbarPage
Fixes #493
2014-06-19 09:36:50 -07:00
Joe Cheng
6e68e07aa2 Merge pull request #512 from yihui/feature/inline-output
Inline output in R Markdown documents
2014-06-19 09:20:13 -07:00
Yihui Xie
86bb010a93 roxygenize 2014-06-19 00:24:10 -05:00
Yihui Xie
4a623b596b ignore width/height in plotOutput() when inline=TRUE, and document required width/height values in renderPlot() 2014-06-19 00:24:10 -05:00
Yihui Xie
bcf098ea7d merge doc of width and height in renderPlot() and plotOutput() 2014-06-19 00:24:10 -05:00
Yihui Xie
4bfb226fb5 roxygenize 2014-06-19 00:24:10 -05:00
Yihui Xie
691615108b preserve the formal arguments of plotOutput() in outputFunc()
otherwise outputFunc() loses the `inline` argument, and knit_print() won't be able to produce inline plots
2014-06-19 00:24:10 -05:00
Yihui Xie
858ab00e36 closes #501: knit_print() for inline output uses the inline argument passed from knitr 2014-06-19 00:24:10 -05:00
Yihui Xie
7023f5b145 add an inline argument to textOutput(), imageOutput(), plotOutput(), and htmlOutput() 2014-06-19 00:24:10 -05:00
Yihui Xie
eb4fabeac6 fix two more staticdocs errors 2014-06-19 00:17:55 -05:00
Joe Cheng
a5e09f9ce4 Merge tag 'v/0/10/0-staticdocs' 2014-06-18 11:12:40 -07:00
Joe Cheng
c2fe4e8b6d Fix staticdoc errors 2014-06-18 11:11:21 -07:00
Winston Chang
5d22648d34 Merge pull request #513 from rstudio/feature/json-precision
Control precision of JSON numeric representation
2014-06-17 11:51:47 -05:00
Yihui Xie
066fd15184 quiet apt-get and install.packages() 2014-06-16 10:32:04 -05:00
Yihui Xie
fe90c230d5 r-base should just work, since the packages that need to be compiled are installed via apt-get 2014-06-16 10:07:54 -05:00
Yihui Xie
0b5ae92136 shiny 0.10.0 is on CRAN now, so the dependencies knitr and htmltools should be automatically detected 2014-06-16 10:05:33 -05:00
Yihui Xie
1c5565aaee a news item for #427 2014-06-16 09:59:32 -05:00
Yihui Xie
69c177a3ec a news item for #516 2014-06-16 09:50:59 -05:00
Joe Cheng
0645b3f65b Merge pull request #507 from yihui/doc/runUrl
Merge doc for runUrl(), runGist(), and runGitHub()
2014-06-16 01:19:52 -07:00
Joe Cheng
9e7471fcc0 Merge pull request #516 from yihui/bugfix/windows-encoding
Fixes #136: I18N support for Windows
2014-06-16 01:17:31 -07:00
Joe Cheng
c520f53799 Bump to development version number 2014-06-16 01:13:33 -07:00
Yihui Xie
0bf1386802 UTF8 encoding for runApp(list(ui, server)) as well 2014-06-13 18:53:36 -05:00
Yihui Xie
b2ab3797aa the cachedSource() function is not used anywhere, so perhaps we can remove it 2014-06-13 18:08:16 -05:00
Yihui Xie
ede0ca8bd1 make sure JSON messages are always encoded and decoded with UTF8
- per @jcheng5's suggestion, RJSONIO::fromJSON(encoding = 'UTF-8') actually works (no longer need my markUTF8 function)
- removed the global option 'shiny.transcode.json'
2014-06-13 18:07:01 -05:00
Yihui Xie
81e35f0cc3 make sure the HTML content is encoded in UTF8 2014-06-13 18:02:20 -05:00
Yihui Xie
237522a1f7 assuming all the input R scripts are UTF8 encoded
ui.R, server.R, and global.R
2014-06-13 18:00:46 -05:00
Joe Cheng
2f94e1d2c9 Fix timing issue with random seed test on windows 2014-06-13 14:40:19 -07:00
Joe Cheng
2689dd32bb Bump version to 0.10.0 2014-06-13 09:41:45 -07:00
Winston Chang
ad5e703b8f Merge pull request #514 from yihui/doc/news-flowLayout
typo: flowPanel --> flowLayout
2014-06-13 11:12:07 -05:00
Yihui Xie
d3bc2e9279 typo: flowPanel --> flowLayout 2014-06-13 11:05:36 -05:00
Joe Cheng
0cd1644cf1 Control precision of JSON numeric representation
Uses 16 digits by default, set shiny.json.digits option to customize
2014-06-10 15:02:45 -07:00
Winston Chang
f02b405c12 Merge pull request #508 from yihui/bugfix/large-margin
set the margin to 0 before plot.new()
2014-06-10 11:57:07 -05:00
Yihui Xie
baa7036799 explain why par(mar = rep(0, 4)) is necessary before plot.new(), per @wch's suggestion 2014-06-10 11:50:49 -05:00
Yihui Xie
431aecaf00 set the margin to 0 before plot.new()
otherwise users will be unable to draw small plots because of the common error "figure margin too large", e.g. renderPlot(..., width=200, height=100)
2014-06-10 00:46:33 -05:00
Yihui Xie
f31bb56ea6 subdir=NULL is the default of runUrl() 2014-06-09 22:24:51 -05:00
Yihui Xie
cf3b805c46 the message is not very useful, given that download() will emit a message 2014-06-09 22:24:51 -05:00
Yihui Xie
517283ca58 closes #427: runGitHub() can accept "username/repo" in its first argument 2014-06-09 22:24:51 -05:00
Yihui Xie
f416b7ba47 the name variable is not used anywhere 2014-06-09 22:21:29 -05:00
Yihui Xie
973190b7a1 let download() fail in this case (ref=NULL); since ref='master' by default, if the user provides another value, he/she is expected to have read the documentation 2014-06-09 22:21:29 -05:00
Yihui Xie
f536a9d3d3 move runGist() and runGithub() after runUrl(), and merge their descriptions into the description of runUrl() 2014-06-09 22:21:29 -05:00
Yihui Xie
1348ec3bcf closes #213: merge the documentation of runUrl(), runGithub(), and runGist()
removed the port and launch.browser arguments, and used ... instead
2014-06-09 21:45:52 -05:00
Joe Cheng
9a250a4861 Merge pull request #506 from yihui/bugfix/stats
stats may not have been loaded in the event of .onLoad()
2014-06-09 09:09:11 -07:00
Yihui Xie
6450927192 stats may not have been loaded in the event of .onLoad() 2014-06-09 10:56:36 -05:00
Joe Cheng
7c9dbdc802 Merge pull request #504 from rstudio/news-update
Update NEWS
2014-06-07 12:29:04 -07:00
Joe Cheng
8d460afe2d Merge pull request #505 from yihui/doc/splitLayout
there should not be #' before @examples
2014-06-06 23:38:00 -07:00
Yihui Xie
6c44c2cf24 there should not be #' before @examples 2014-06-07 01:00:13 -05:00
Joe Cheng
cea550ebba Update NEWS 2014-06-06 22:41:04 -07:00
Joe Cheng
911a352ee6 Bump version 2014-06-06 22:20:17 -07:00
Joe Cheng
3fadfbe06e Merge pull request #503 from rstudio/bugfix/shinyapps-in-tags-2
Allow shinyApp objects to appear inside tags
2014-06-06 22:16:35 -07:00
Joe Cheng
5bf362927f Allow shinyApp objects to appear inside tags 2014-06-06 15:23:13 -07:00
Yihui Xie
4da5ca5ba9 bump version 2014-06-06 17:07:17 -05:00
Yihui Xie
d747005b30 copy the documentation of knit_print methods from htmltools, too 2014-06-06 17:07:10 -05:00
Yihui Xie
03a395107d export knit_print methods imported from htmltools 2014-06-06 16:59:12 -05:00
Yihui Xie
58ef4ccabf declare the method through @method per @hadley's suggestion at klutometis/roxygen#256 2014-06-04 16:30:12 -05:00
Yihui Xie
71ed082bb5 bump version 2014-06-04 15:41:33 -05:00
Yihui Xie
0819ac8124 no need to assign a copy of these functions in shiny, because we have imported htmltools, and we only need to export the imported functions 2014-06-04 15:38:41 -05:00
Yihui Xie
0cdd223172 cosmetic changes after #481, and roxygenize 2014-06-04 15:30:15 -05:00
Yihui Xie
571393f146 htmltools was in both Depends and Imports, against which R CMD check will warn
I guess it was in Depends because otherwise as.tags could not be treated as an S3 generic; sounds like a bug of roxygen2 or devtools
2014-06-04 15:30:15 -05:00
Yihui Xie
c85868c652 use @export instead of @S3method 2014-06-04 15:10:45 -05:00
Joe Cheng
a7a6f3b020 Merge pull request #499 from yihui/bugfix/456
Bugfix/456
2014-06-03 10:01:44 -07:00
Yihui Xie
3a0a11d55a introduce an equivalent function to achieve set.seed(NULL) in R 2.15.x 2014-06-02 16:14:22 -05:00
Yihui Xie
7eb8ddf372 fixes #456: use .Random.seed only if it exists in the global environment
e.g. the expr may not trigger the creation of .Random.seed, such as set.seed(NULL) under R 2.15.x, which will fail
2014-06-02 16:13:37 -05:00
Yihui Xie
87af63644a bump version 2014-06-02 15:38:40 -05:00
Yihui Xie
0a9dd18070 news for #433 2014-06-02 15:36:36 -05:00
Yihui Xie
f82b061ba7 news for #481 2014-06-02 15:18:54 -05:00
Yihui Xie
c17509e2a0 news for #495 2014-06-02 15:18:54 -05:00
Yihui Xie
cb383d4f62 serverInfo() returns list(shinyServer=FALSE) by default, per suggestion of @trestletech 2014-06-02 15:18:54 -05:00
Yihui Xie
451f950d0d tweak after #492: capture.output() does withVisible() and print() if necessary 2014-06-02 15:18:54 -05:00
Yihui Xie
bd0eae0961 Merge pull request #481 from saurfang/master
Add inline option for RadioButton and checkboxGroupInput
2014-06-02 15:03:40 -05:00
Joe Cheng
53a401f847 Merge pull request #495 from yihui/feature/serverInfo
add functions serverInfo() (exported) and setServerInfo() (not exported)
2014-06-02 09:16:51 -07:00
JJ Allaire
b288f5ca19 bump version 2014-06-02 08:11:02 -04:00
JJ Allaire
7a2fc19c4f bump version 2014-06-01 10:00:40 -04:00
JJ Allaire
046d712d6a Revert "Allow Shiny apps to appear inside other tags"
This reverts commit 9ab2f5338e.
2014-06-01 09:59:50 -04:00
Joe Cheng
e829aaecf1 Install htmltools in travis script 2014-05-31 10:58:54 -07:00
Joe Cheng
9ab2f5338e Allow Shiny apps to appear inside other tags 2014-05-31 09:06:54 -07:00
Joe Cheng
d7bda924be Depend on htmltools, not just Import
This seems to be necessary to get the knit_print.shiny.tags to work
with Rmarkdown without an explicit library(htmltools)
2014-05-31 08:26:09 -07:00
Joe Cheng
07eb2e51b7 Bump version to 0.9.1.9009 2014-05-31 08:08:08 -07:00
Joe Cheng
dfafa7ae40 Merge branch 'htmltools-refactor' 2014-05-31 08:06:56 -07:00
Joe Cheng
dde266768c Restore HTML generating functions
These functions were temporarily ripped out of Shiny and moved
to the htmltools package. We've discovered that it's safe to
keep including them in shiny; as long as the functions in shiny
and the functions in htmltools are identical, the user won't
receive a conflict warning.
2014-05-31 08:06:03 -07:00
Joe Cheng
01c81675f7 Make S3 method consistent with base 2014-05-31 08:06:03 -07:00
Joe Cheng
71972eb362 Update htmltools version 2014-05-31 08:06:03 -07:00
Joe Cheng
eb9f5f9025 Dependency fixes
1) Give bootstrap deps a path so they can be used in static docs
2) Resolve dependencies before rendering page (whoops)
2014-05-31 08:06:03 -07:00
Joe Cheng
eb4d4d7437 Adapt to htmltools 0.2.1 API 2014-05-31 08:06:03 -07:00
Joe Cheng
1cb5e09109 Remove obsolete entry from staticdocs index 2014-05-31 08:06:03 -07:00
Joe Cheng
cc82fff5d3 Add S3 method for turning render function into tags 2014-05-31 08:06:03 -07:00
Joe Cheng
3212e59dcc Fix broken client-side HTML dependency rendering 2014-05-31 08:06:03 -07:00
Joe Cheng
44a795bf18 Extract HTML functionality to htmltools library 2014-05-31 08:06:03 -07:00
Joe Cheng
376e6f35a2 Merge pull request #496 from eiriksm/travis-fix
Use svg version of build status. Only show master build status.
2014-05-31 08:03:16 -07:00
Eirik S. Morland
3b324e9532 Use svg version of build status. Only show master build status. 2014-05-31 12:04:00 +02:00
Joe Cheng
a0df8f3490 Merge pull request #491 from rstudio/bugfix/validation-silent
Suppress validation errors from printing at console
2014-05-28 13:14:02 -07:00
Winston Chang
6c14789362 Merge pull request #492 from rstudio/bugfix/0.10misc
Miscellaneous bug fixes
2014-05-23 14:13:29 -05:00
Winston Chang
880a12b914 Merge pull request #489 from yihui/bugfix/428
Fixes #428
2014-05-23 14:09:43 -05:00
Joe Cheng
93d69400e6 Merge pull request #486 from yihui/feature/widget-width
Width of selectize and sliders
2014-05-22 15:43:34 -07:00
Joe Cheng
d4829e49ea Doc tweak to validation 2014-05-21 19:57:18 -07:00
Joe Cheng
1c56be3a6b Suppress validation errors from printing at console 2014-05-21 19:51:24 -07:00
Joe Cheng
07a0dfddc7 Validation error causes real errors to look like validation errors
The CSS class for validation errors was not being properly removed between different kinds of errors
2014-05-21 19:32:44 -07:00
Joe Cheng
b86f9086ef Avoid black background when renderPlot doesn't actually plot 2014-05-21 19:28:51 -07:00
Joe Cheng
343ca12c6f Don't print NULL to the console during renderPrint 2014-05-21 19:28:28 -07:00
Joe Cheng
af3c4f84b6 Merge pull request #488 from yihui/bugfix/220
fix #220: the first entry in zip is not necessarily a directory
2014-05-20 00:32:11 -07:00
Yihui Xie
3679e8795f fix #220: the first entry is not necessarily a directory
in that case, we use dirname() on the first entry
2014-05-20 01:43:48 -05:00
Yihui Xie
39b4805a76 make sure the selected argument never contains names; fixes #428 2014-05-20 01:31:14 -05:00
Yihui Xie
3bdcdf96d4 upgrade selectize.js to v0.9.1 to fix the third issue in #428 2014-05-20 01:30:37 -05:00
Yihui Xie
b54e5d33bc roxygenize 2014-05-19 11:25:40 -05:00
Yihui Xie
85e020a513 examples of the 'width' argument 2014-05-19 11:24:56 -05:00
Yihui Xie
5b6268f5bc add width to selectInput() as well 2014-05-19 11:23:52 -05:00
saurfang
063b58eebb Merge remote-tracking branch 'upstream/master' 2014-05-17 16:33:25 -04:00
Yihui Xie
f8b38e4683 validateCssUnit(width) for selectize and slider 2014-05-17 01:32:01 -05:00
Yihui Xie
18e85c32b4 roxygenize 2014-05-17 01:28:27 -05:00
Yihui Xie
831fba9a53 add a 'width' option to selectizeInput() and sliderInput() to specify the width of these widgets 2014-05-17 01:28:27 -05:00
Joe Cheng
b1f233cd8c Merge remote-tracking branch 'origin/pr/485'
Conflicts:
	NEWS
2014-05-16 23:22:01 -07:00
Yihui Xie
3d0caba695 \emph cannot be used in \code{}: only \var and \link are allowed 2014-05-17 00:53:57 -05:00
Yihui Xie
79c92f1f8e fixes #429, which is yet yet another WAT of RJSONIO
perhaps we really should consider switching to jsonlite...
2014-05-17 00:43:13 -05:00
Yihui Xie
87f26e47bb a news item for the 'width' argument of renderPrint() 2014-05-16 14:19:55 -05:00
Yihui Xie
9d8d04ae28 add a 'width' argument so we can control the width of the text output 2014-05-16 14:17:50 -05:00
Yihui Xie
a42f046ff8 capture.output() has already considered withVisible(), and we do not need to redo it 2014-05-16 14:12:50 -05:00
Yihui Xie
01c24a578b add functions serverInfo() (exported) and setServerInfo() (not exported)
we can call shiny:::setServerInfo() in Shiny Server before launching an app, so that the app author can make use of the info to decide the behavior of the app
2014-05-16 13:22:22 -05:00
saurfang
6b82354129 Merge remote-tracking branch 'upstream/master' 2014-05-15 12:30:52 -04:00
Joe Cheng
b00fbda1ae Make sure random bytes are formatted with 2 chars 2014-05-14 17:11:18 -07:00
saurfang
bab200ff03 Merge remote-tracking branch 'upstream/master' 2014-05-14 15:44:23 -04:00
Joe Cheng
357e81aeca Bump version 2014-05-14 09:14:19 -07:00
Joe Cheng
3189c748b5 Merge pull request #479 from rstudio/not-just-last-expressions
Allow shinyUI and shinyServer calls to not be the last expression in ui....
2014-05-14 09:06:28 -07:00
Joe Cheng
2700643cbf Merge pull request #480 from jcheng5/bugfix/renderplot-height-overlap
Fix #477: renderPlot in shinydoc with height > 400 overlaps subsequent c...
2014-05-14 09:06:15 -07:00
saurfang
b0f95cd9e0 Add inline options
inline options for radiobuttons and checkboxgroupinput to allow choices
rendered horizontally
2014-05-13 17:18:20 -04:00
Winston Chang
ff628ac0b2 Fixes for jshint 2014-05-12 20:46:24 -05:00
Joe Cheng
f21aefe9e9 Merge pull request #467 from yihui/cosmetic
Some cosmetic changes regarding NULL
2014-05-10 02:13:25 -07:00
Joe Cheng
8babbd69d8 Merge branch 'session-documentation'
Conflicts:
	inst/staticdocs/index.r
2014-05-09 19:41:19 -07:00
Joe Cheng
11bf02eb56 Merge pull request #478 from rstudio/remove-literate-programming
Stop using literate programming
2014-05-09 19:39:58 -07:00
Joe Cheng
f5fa7d6d4b Fix #477: renderPlot in shinydoc with height > 400 overlaps subsequent content 2014-05-09 18:14:28 -07:00
Joe Cheng
77bff6e6c2 Allow shinyUI and shinyServer calls to not be the last expression in ui.R and server.R 2014-05-08 16:14:53 -07:00
Joe Cheng
e84a76cebd Merge pull request #457 from yihui/feature/unsatisfied-input
A first attempt of the custom error type for unsatisfied input dependencies
2014-05-08 16:12:58 -07:00
Yihui Xie
342265be94 put the custom class(es) in the first as Hadley suggested 2014-05-08 15:04:49 -07:00
Yihui Xie
62ec9291d8 Merge pull request #1 from jcheng5/feature/unsatisfied-input
Refactoring/renaming of validation
2014-05-08 14:57:54 -07:00
Joe Cheng
dee6fbcb8f Stop using literate programming
Couldn't build from source without knitr installed, and knitr
is not a required dependency
2014-05-08 14:54:11 -07:00
JJ Allaire
72fa9a2dcb bump version 2014-05-08 12:54:20 -04:00
Joe Cheng
ca27a9e31a Validation refactoring
- Move validation logic from shinywrappers.R to utils.R
- Don't coerce validation results; fail if not FALSE, NULL, or character
- Reverse order of stopWithCondition args
2014-05-07 16:20:07 -07:00
Joe Cheng
18d0f45cf9 Refactoring/renaming of validation
- validateInput renamed to validate
- validateCondition renamed to need
- Removed ability to provide "bare" conditions. It is
  still possible to fail validation silently by passing
  FALSE as the second argument to need()
- Rather than using a two-element list to convey results,
  use a single result protocol; NULL is success, FALSE is
  silent failure, string is failure with message
- Tweak "missing input" semantics, add tests
2014-05-07 16:09:06 -07:00
Joe Cheng
424fd515a4 Merge pull request #472 from rstudio/bugfix/delayed-assign-2
Remove delayedAssign which causes problems for downstream packages
2014-05-07 09:56:19 -07:00
Joe Cheng
00b40d64a1 Remove delayedAssign which causes problems for downstream packages
See comment on d7eb9b2d18
2014-05-06 20:40:57 -07:00
Joe Cheng
3a7d0a5a9f Document session object
Also allow http handlers to return standard Rook responses instead of
httpResponse objects.
2014-05-06 11:56:23 -07:00
Joe Cheng
57a02318e3 Clearer error message when shinyAppDir is given a nonexistent path 2014-05-05 15:31:21 -07:00
Joe Cheng
8f6d8cf0d6 Slider with label=NULL doesn't have tag classes attached 2014-05-05 14:00:43 -07:00
Joe Cheng
5b6605b296 Add inputPanel to staticdocs index 2014-05-05 13:59:46 -07:00
Joe Cheng
4d83596595 Merge pull request #465 from rstudio/feature/horizontal-layout
New layouts for horizontal placement
2014-05-05 13:10:26 -07:00
Joe Cheng
7e12a281f5 Remove slider from bundled jquery-ui 2014-05-05 12:12:41 -07:00
Joe Cheng
c63c10e48a Merge pull request #466 from rstudio/bugfix/space-urls
Encode pathname when necessary on browsers that supply it decoded
2014-05-05 11:40:06 -07:00
Joe Cheng
155554f0b7 Only double-encode on Qt 2014-05-05 11:36:27 -07:00
Yihui Xie
26b0836756 since NULL in tag() will be dropped, there is no need to check is.null(icon) 2014-05-03 01:11:32 -05:00
Yihui Xie
a87dc9bab2 cosmetic: both if (FALSE) expr and for-loops return NULL 2014-05-03 01:09:51 -05:00
Yihui Xie
9c1555a110 tweak an RStudio project option 2014-05-03 00:54:44 -05:00
Joe Cheng
fbda2db884 Only show special "No UI defined" message for shinyAppDir 2014-05-02 18:52:37 -07:00
Joe Cheng
2a229774ef Merge pull request #463 from jcheng5/bugfix/faster-select
Massively faster selectInput
2014-05-02 17:31:38 -07:00
Joe Cheng
137e5b13ef Update tests 2014-05-02 17:28:01 -07:00
Joe Cheng
7920d66cd0 Separate option tags with newline 2014-05-02 17:26:27 -07:00
Yihui Xie
9f2dae7f3b the logic of the last commit was not correct: we should not stop immediately on a non-condition object; instead, we still need to collect all messages on all conditions before we stop 2014-05-02 18:13:35 -05:00
Yihui Xie
ffde0ad1f5 roxygenize 2014-05-02 17:56:20 -05:00
Yihui Xie
2c2658a8ec rewrite the lapply()/vapply() with a plain dumb for-loop 2014-05-02 17:54:05 -05:00
Yihui Xie
6f2f8f6f7a add a function validateCondition() to avoid ambiguity
two advantages:

1. we no longer need to worry about input$foo being a list;
2. users have to explicitly call validateCondition() when they want error messages, so we know when to silently stop;
2014-05-02 17:33:29 -05:00
Yihui Xie
4b6dcdd1b0 use shiny-output-error as the _prefix_ for CSS classes of error messages 2014-05-02 16:56:43 -05:00
Yihui Xie
de346fd6c3 filter out some common error classes 2014-05-02 16:56:43 -05:00
Yihui Xie
bf9d7c2012 use the classes of the error condition as names of CSS classes in the output 2014-05-02 16:56:43 -05:00
Yihui Xie
143803f86d factor out stop() code to a separate function 2014-05-02 16:56:43 -05:00
Yihui Xie
311143451d condition first, message second 2014-05-02 16:56:43 -05:00
Jonathan McPherson
c9030f401d encode pathname when necessary on browsers that supply it decoded 2014-05-02 14:41:11 -07:00
Joe Cheng
8668ddce74 Tweak padding 2014-05-02 12:21:34 -07:00
Joe Cheng
7a495357f7 Update NEWS, tweak description for flowLayout 2014-05-02 12:06:15 -07:00
Joe Cheng
13864a811d Add inputPanel 2014-05-02 12:06:15 -07:00
Joe Cheng
5b65e4b250 Replace horizontalLayout with flowLayout; add splitLayout 2014-05-02 12:06:15 -07:00
Joe Cheng
dfe4a80501 Update NEWS 2014-05-02 12:06:15 -07:00
Joe Cheng
bf82b9742a Use standardized widths for selectize/jslider
The 100% width worked well inside of a sidebar, but in other situations
like full-width columns or zero-min-width tables a fixed width is better.
If there's demand we can add parameters for setting the width to custom
values including 100%.
2014-05-02 12:06:14 -07:00
Joe Cheng
829a466f72 New horizontalLayout function; put elements in a single table row 2014-05-02 12:06:14 -07:00
Yihui Xie
1206c70c42 we -> you 2014-05-02 12:45:35 -05:00
Joe Cheng
3c32c349b9 Always use Rscript from R_HOME 2014-05-02 09:12:28 -07:00
Yihui Xie
0709f08d65 a custom type of errors for unsatisfied input dependencies 2014-05-01 18:13:56 -05:00
Joe Cheng
50f78c6e40 Make tabsetPanel result visible
Without this, they don't show up in knitr documents
2014-05-01 14:31:25 -07:00
Joe Cheng
7e7afc6d38 Massively faster selectInput 2014-05-01 14:16:27 -07:00
Winston Chang
1130eadac8 Bump version 2014-04-30 14:35:08 -05:00
Winston Chang
959fc2bbb2 Merge pull request #459 from jcheng5/naked-render-in-tags
Allow naked renderXXX functions to be used inside other tags
2014-04-30 13:24:38 -05:00
Joe Cheng
f8ae505011 Change all "is()" calls to "inherits()"
According to ?inherits
2014-04-30 11:19:49 -07:00
Joe Cheng
cd183a1926 Merge branch 'feature/mask-reactive-context'
Conflicts:
	NEWS
2014-04-30 11:14:50 -07:00
Joe Cheng
bb2796fbc3 Add tests 2014-04-30 11:14:20 -07:00
Joe Cheng
5de7103890 Upgrade jqueryui to 1.10.4 and remove datepicker
The jqueryui datepicker collides with our bootstrap datepicker

Reviewed by @wch
2014-04-30 11:07:51 -07:00
Joe Cheng
a78c91ba7e Make renderPlot print result if visible
Reviewed by @wch
2014-04-30 10:10:06 -07:00
Joe Cheng
fca50da57b Fix staticdoc test 2014-04-29 12:09:37 -07:00
Joe Cheng
61f2c908b1 Add maskReactiveContext function 2014-04-29 12:01:03 -07:00
Joe Cheng
4c096ac068 Merge pull request #454 from yihui/feature/selectize-more
Make `selected` work for server-side selectize input
2014-04-28 15:41:19 -07:00
Jonathan
2c95678be1 Merge pull request #451 from jcheng5/suppress-reactlog
Don't send reactlog messages to the client unless showcase mode
2014-04-28 14:52:42 -07:00
Joe Cheng
1a643cecf3 Allow naked renderXXX functions to be used inside other tags 2014-04-28 10:13:16 -07:00
Joe Cheng
aa10b2e8c4 Merge pull request #455 from trestletech/feature/subapp
Added extra query param to identify sub apps.
2014-04-28 09:33:37 -07:00
Joe Cheng
0b9317d047 Merge pull request #453 from yihui/feature/nocache
Prevent caching conditionally
2014-04-28 09:33:03 -07:00
Yihui Xie
4d58f05f38 fix the warning about stats not being imported in namespace
see https://travis-ci.org/rstudio/shiny/builds/23791246

but do we even have to import stats? I guess no; it is part of base R
2014-04-25 18:26:07 -05:00
trestletech
6e879c8156 Added extra query param to identify sub apps. 2014-04-25 11:30:48 -05:00
Yihui Xie
b6ee67aa41 make the selected argument of updateSelectizeInput() work even in the server mode 2014-04-25 02:38:38 -05:00
Yihui Xie
07bed0c7c7 factor out a function columnToRowData() so both updateSelectInput() and selectizeJSON() can use it 2014-04-25 02:37:45 -05:00
Yihui Xie
d2bd59d149 Make meta of length 0 when we are sure there are no dependencies
knitr::asis_output() will decide whether x is cacheable by checking length(meta) == 0. Some shiny tags are cacheable, such as numericInput(), because it is pure HTML without dependencies, whereas selectizeInput() is not cacheable due to the dependency on selectize.js.
2014-04-25 01:14:14 -05:00
Yihui Xie
7bdac5a44e Make sure shiny app objects are not cacheable using asis_output(..., cacheable = FALSE)
This commit reverts d08a2507fa
2014-04-25 01:14:08 -05:00
Joe Cheng
51f5db4374 Bump version 2014-04-24 16:38:07 -07:00
Joe Cheng
e395ae6555 Merge branch 'html-deps'
Code reviewed by @jmcphers

Conflicts:
	DESCRIPTION
	R/bootstrap.R
	R/reactives.R
2014-04-24 16:37:46 -07:00
Joe Cheng
1df9c498cf Ensure dep.meta is an array 2014-04-24 16:32:18 -07:00
Joe Cheng
57b3b919a5 Don't send reactlog messages to the client unless showcase mode 2014-04-24 16:05:54 -07:00
Joe Cheng
00c6bbb297 Merge pull request #449 from rstudio/bugfix/knitr-cached-shiny
Fail when attempting to insert a Shiny app into a cached knitr chunk
2014-04-24 15:50:05 -07:00
Joe Cheng
b6536a0af3 Merge pull request #445 from wch/str
Add str.reactivevalues
2014-04-24 15:49:21 -07:00
Jonathan McPherson
d08a2507fa fail when attempting to insert a shiny app into a cached chunk 2014-04-24 15:28:07 -07:00
Joe Cheng
8bc8829577 Merge pull request #448 from trestletech/rate-element
Add element argument to getRateCallback()
2014-04-24 10:01:42 -07:00
trestletech
c843e6f68c Bump version 2014-04-24 10:58:36 -05:00
trestletech
84583e5501 Add element argument to getRateCallback() 2014-04-24 10:13:06 -05:00
Winston Chang
4548562138 Fix argument name for S3 method 2014-04-23 15:03:49 -05:00
Joe Cheng
32c170b10a Remove Rmd examples 2014-04-23 13:02:40 -07:00
Joe Cheng
97dafa0a55 Include html-preserving comments in knit_print 2014-04-23 12:46:56 -07:00
Yihui Xie
0be1ee46f2 do not ignore the names of choices data 2014-04-22 17:58:19 -05:00
Winston Chang
34c9ab7643 Add str.reactivevalues 2014-04-21 21:59:49 -05:00
Joe Cheng
59dbca250f Fix roxygen 2014-04-21 16:50:06 -07:00
Joe Cheng
4028dbfda1 Do typeset mathjax on initial load
Fixes initial load not being typeset on e.g.:
https://gist.github.com/jcheng5/a0d123d58737590ac21e
2014-04-21 13:59:17 -07:00
Joe Cheng
b9dbf610b0 Fix bootstrap themes 2014-04-21 13:16:34 -07:00
Joe Cheng
d443810520 Use html_dependency for date inputs, datatables 2014-04-21 12:35:12 -07:00
Joe Cheng
fcd941d33d Use html_dependencies for showcase mode
For some reason, showcase mode was breaking sliders without this (e.g. 06_tabsets)
2014-04-21 12:34:54 -07:00
Yihui Xie
9c063fa37c bump version 2014-04-21 01:02:46 -05:00
Yihui Xie
2720cfe346 should use MathJax.Hub.Queue() instead of .Typeset(): finally solved the mysterious race condition issue
http://docs.mathjax.org/en/latest/typeset.html
2014-04-21 01:02:05 -05:00
Joe Cheng
c39e38081e Remove unused class 2014-04-18 16:29:13 -07:00
Joe Cheng
3deb4c3f42 Fix initial dependency handling, fix knit_print 2014-04-18 16:21:13 -07:00
Joe Cheng
6945091238 First attempt at HTML dependency management 2014-04-18 15:18:51 -07:00
JJ Allaire
c758c4785a bump version 2014-04-17 07:38:06 -04:00
Jonathan McPherson
19269a20fb fix subapps on portmapped URLs
Reviewed by @jcheng5
2014-04-16 13:08:57 -07:00
Joe Cheng
45669cacb1 Merge pull request #434 from jcheng5/private-random
Refactor private random seed code
2014-04-15 15:24:41 -07:00
Joe Cheng
840bc52aae Merge pull request #433 from yihui/selectize/server
server-side selectize input
2014-04-15 15:22:11 -07:00
Joe Cheng
bbc36e349f Merge pull request #439 from jcheng5/feature/uiPattern
Add uiPattern param to shinyApp to allow one ui to serve multiple URLs
2014-04-15 15:13:08 -07:00
Joe Cheng
a4325adcdd Add uiPattern param to shinyApp to allow one ui to serve multiple URLs
Reviewed by @jmcphers
2014-04-15 12:53:18 -07:00
Yihui Xie
23f39649d0 Merge pull request #438 from jcheng5/fix-roxygen
Fix PriorityQueue error message during roxygenize
2014-04-15 00:12:43 -05:00
Yihui Xie
87b09a534e Merge pull request #435 from jcheng5/null-input-labels
Allow NULL input labels; add actionLink
2014-04-14 22:59:28 -05:00
Yihui Xie
39f0e5ae0c fix some JShint issues 2014-04-14 22:53:08 -05:00
Yihui Xie
62aaab0926 closes #422: update the selectize options via updateSelectizeInput(options) 2014-04-14 22:34:48 -05:00
Yihui Xie
cddfe999aa cosmetic changes (re-indent code) 2014-04-14 22:28:45 -05:00
Joe Cheng
fcbb658ac2 Fix PriorityQueue error message during roxygenize 2014-04-14 15:37:06 -07:00
Joe Cheng
3bbf06ba49 Don't indent HTML during knit_print 2014-04-14 15:31:45 -07:00
Yihui Xie
d9be6f1d2e implementing the server-side selectize input
also added a new method shinysession$registerDataObj(), which was designed to be a general data retrieval method: we can store arbitrary data objects as "downloads", and return arbitrary http response based on the filter function; see renderDataTable() and updateSelectizeInput() for two examples
2014-04-13 00:02:08 -05:00
Yihui Xie
5d70e68a0b the development version of knitr can be installed from rforge.net 2014-04-12 12:33:42 -05:00
Joe Cheng
529f2325b2 Fix tests 2014-04-11 15:46:32 -07:00
Joe Cheng
314d433f86 Merge pull request #436 from rstudio/feature/shiny-docs
Improved support for R Markdown Shiny documents
2014-04-11 15:43:43 -07:00
Jonathan McPherson
12ea950c5f use more idiomatic syntax for resolving rmarkdown.runtime 2014-04-11 14:41:06 -07:00
Yihui Xie
f4d12220ca Merge pull request #437 from trestletech/winslash
Make normalizePath calls Windows-compatible.
2014-04-11 15:41:54 -05:00
Jonathan McPherson
6a9cba90f4 have validateCssUnit treat unit-free character strings as pixel units 2014-04-11 12:59:15 -07:00
trestletech
6873e1f1cb Make normalizePath calls Windows-compatible. 2014-04-11 14:55:51 -05:00
Joe Cheng
fa0a91a75d Fix createUniqueId logic 2014-04-11 12:06:22 -07:00
Joe Cheng
020bb659c5 Rename tempSet to withTemporary 2014-04-11 12:00:55 -07:00
Joe Cheng
b1d6687fb0 Fix private random seed mechanism
- Introduce randomInt/p_randomInt to generate random integers in a half-open range
- Stop using runif to generate integers
- Explicitly reset the private seed during .onLoad. I was getting the same "random" numbers from Shiny every time I restarted R!
2014-04-11 11:57:39 -07:00
Joe Cheng
f67e17b287 Allow NULL input labels; add actionLink 2014-04-11 11:00:41 -07:00
Jonathan McPherson
81bd57c5ea emit appropriate warnings in R Markdown mode; collect <head> contents 2014-04-11 10:53:25 -07:00
Joe Cheng
d803bae874 Bump ver 2014-04-11 10:17:51 -07:00
Joe Cheng
14606f4087 Remove unnecessary ::: 2014-04-11 10:16:59 -07:00
Joe Cheng
599fdc7ee5 Refactor private random seed code 2014-04-10 15:03:18 -07:00
Joe Cheng
722e205db5 Isolate createUniqueId randomness from rest of R
TODO: Generalize to our own runif

Reviewed by @jmcphers
2014-04-09 17:16:36 -07:00
Joe Cheng
f67849eb47 Doc cleanup 2014-04-09 17:10:37 -07:00
Joe Cheng
662ca4e40a Fix travis? 2014-04-09 16:28:36 -07:00
Joe Cheng
aa61be74d8 Merge pull request #432 from jcheng5/multiple-apps
Support reactive documents and embedded Shiny apps in rmarkdown
2014-04-09 16:23:43 -07:00
Joe Cheng
10296fcd6b Clear handler manager anytime runApp is called 2014-04-09 16:10:43 -07:00
Joe Cheng
f8bf146b6c Render functions can be inserted directly into .Rmd
All render functions need to call markRenderFunction on their
return values for this mechanism to work.

Also:
- Remove runRmdContainer (it's moved to rmarkdown)
- Remove some bad .Rbuildignore entries
- Make height/width in shinyApp respected
2014-04-09 14:53:56 -07:00
Joe Cheng
52f104c517 Automatically remove subapps when their owning session finishes 2014-04-08 16:38:45 -07:00
Joe Cheng
6c1fc224f0 Merge pull request #1 from jcheng5/reactive-domains
Reactive domains
2014-04-08 15:44:51 -07:00
Joe Cheng
6b9ae3a8b3 Move "@include globals.R" directives to top; slight doc fixes 2014-04-08 15:39:57 -07:00
Joe Cheng
07f73030c6 More reactive domain work
- observers' autodestroy behavior is now optional
- tests
2014-04-08 14:47:32 -07:00
Joe Cheng
47130c79ee Code review feedback 2014-04-08 11:16:42 -07:00
Joe Cheng
f3a3bdfe4f Port showcase mode execution highlighting to domains 2014-04-07 21:59:16 -07:00
Joe Cheng
e5e54fe4c1 Implement reactive domains 2014-04-07 21:55:05 -07:00
Joe Cheng
29c0f9a43a Ignore additional knit_print parameters 2014-04-07 17:10:44 -07:00
Joe Cheng
0b78229c77 Travis!! *shakes fist* 2014-04-07 11:45:46 -07:00
Joe Cheng
c2a1d70070 Fix travis 2014-04-07 10:54:21 -07:00
Joe Cheng
260ecd1d9f Travis: Install latest knitr master 2014-04-07 09:24:51 -07:00
Joe Cheng
3dce2e761a Fix debugging of server files
.global$server becomes appvars$server
2014-04-04 10:30:42 -07:00
Joe Cheng
80a54200ce Comment tweaks 2014-04-03 23:45:08 -07:00
Joe Cheng
51227d438a Get rid of "incomplete final line" warnings in showcase code 2014-04-03 21:33:40 -07:00
Joe Cheng
6fb4199d37 Make the worker ID global across all sub apps 2014-04-03 21:30:56 -07:00
Joe Cheng
6ba46aff6b Fix gitignores for literate 2014-04-03 21:02:18 -07:00
Joe Cheng
5da34d0646 Fix makefile on windows 2014-04-03 20:43:55 -07:00
Joe Cheng
f215088939 Update staticdocs index, tests pass 2014-04-03 19:43:11 -07:00
Joe Cheng
df34dcdb0c Pass R CMD check 2014-04-03 19:37:45 -07:00
Joe Cheng
89f464af99 Fix Rmd build tooling 2014-04-03 15:31:49 -07:00
Joe Cheng
3f6f02f7d2 More docs 2014-04-03 14:41:59 -07:00
Joe Cheng
0d861e5389 Add documentation for handlers/middleware 2014-04-03 14:24:55 -07:00
Joe Cheng
b290c8700c Allow the use of .Rmd files for shiny impl scripts 2014-04-03 11:12:16 -07:00
Joe Cheng
81b6fbe263 Remove obsolete print.shiny.appdir 2014-04-03 01:51:30 -07:00
Joe Cheng
b3af293f66 Fix scoping bug 2014-04-03 01:49:36 -07:00
Joe Cheng
b187485172 Major refactor of runApp/addSubApp pipeline
- shinyUI and shinyServer calls are no longer required in ui.R and server.R
- shinyAppObj renamed to shinyApp
- runApp can take pathname, list(ui=..., server=...), shinyApp, and shinyAppDir
  as appDir argument
- Unify all Shiny app representations around shiny.appobj
- BREAKING CHANGE: shinyUI no longer has a "path" argument
- Instead of returning UI, ui.R can return a function that returns UI; it will
  be invoked each time the page is requested. (Note that this is NOT the same
  as saying ui.R will be run each time the page is requested.) The function can
  take either no args or a single "req" arg which is the request.
2014-04-03 01:42:01 -07:00
Joe Cheng
b449d9759c Minor doc updates 2014-04-01 23:02:22 -07:00
Joe Cheng
d9d63a3a2e Painful refactoring of server.R
This refactor changes the level of abstraction where sub-apps are implemented.
Sub-apps can basically be thought of as routing (previously called "proxying"
which was way too confusing). A call comes in to /1e8f937a8934/ and it matches
a sub-app path--we need to change the path from /1e8f937a8934/ to / for the
duration of the sub-app's handling of the request.

We used to do routing (nee proxying) at the httpuvCallback level, which added
a lot of complexity because it meant we were compositing HTTP handlers at both
the httpHandler level, and then again at the httpuvCallback level. This
refactor changes it so nobody speaks the language of httpuv except at the very
boundary of Shiny (webserver$createHttpuvApp), everything inside is either an
httpHandler or a wsHandler. So whether you're combining or routing or whatever,
everything now works the same way.
2014-04-01 22:55:56 -07:00
Joe Cheng
fd7b54fb77 Clean up exports, examples 2014-03-31 16:40:17 -07:00
Joe Cheng
887f8a606d Restore index.r entries for app obj 2014-03-31 12:11:16 -07:00
Joe Cheng
7e3717243f Merge remote-tracking branch 'origin/master' into multiple-apps
Conflicts:
	staticdocs/index.r
2014-03-31 12:08:59 -07:00
Joe Cheng
221849aa3a More-correct impl of %OR% 2014-03-31 12:07:57 -07:00
Joe Cheng
b52d40ab28 Merge pull request #430 from rstudio/v0.10
V0.10
2014-03-31 11:55:29 -07:00
Joe Cheng
3ed68ffd92 knit_print tags and tagLists 2014-03-31 11:17:24 -07:00
Joe Cheng
cc3cd2c141 Implement Shiny apps embedded as iframes in knitr 2014-03-31 10:03:22 -07:00
Winston Chang
5e30f7efc4 Merge pull request #424 from rstudio/bugfix/zero-arg-sourcerefs
Handle zero-argument outputs gracefully
2014-03-27 12:48:41 -05:00
Yihui Xie
35090251ef basically library(pkg) = if (!require(pkg)) stop() 2014-03-24 23:49:34 -05:00
Yihui Xie
338afb4893 change the deprecated @S3method to @export 2014-03-24 23:46:46 -05:00
Yihui Xie
194d8a05f8 using the latest master of klutometis/roxygen (d823c3a088b20ea5e38a60d78d42ccbe9f1e1eec)
Rd text for arguments is no longer wrapped by default
2014-03-24 23:46:46 -05:00
Winston Chang
93e276bd9b Fix capitalization of markdown package 2014-03-24 12:35:12 -05:00
Winston Chang
a69517519c Add more information to selectInput docs 2014-03-21 16:30:25 -05:00
Winston Chang
f646b1efb4 Bump version to 0.9.1.9000 for development 2014-03-21 16:16:53 -05:00
Jonathan McPherson
fc9bedacc0 guard against null source references 2014-03-20 16:00:51 -07:00
Jonathan McPherson
795eeee809 handle no-argument output calls gracefully 2014-03-20 15:46:25 -07:00
Joe Cheng
6d7818962e Redirect on no trailing slash 2014-03-20 10:14:02 -07:00
Joe Cheng
068517c933 Prevent multiple apps from stomping on server func 2014-03-20 09:09:54 -07:00
Joe Cheng
5b030200df initial prototyping of subapps 2014-03-20 08:49:18 -07:00
Joe Cheng
c732122966 Merge pull request #421 from jcheng5/bugfix/context-new
Fix 'Error in Context$new : could not find function "loadMethod"'
2014-03-19 11:40:19 -07:00
Joe Cheng
d7eb9b2d18 Fix 'Error in Context$new : could not find function "loadMethod"'
This warning was happening to dependent packages on R CMD check.

The problem is due to delayedAssign; it appears this can't be used safely, at least not to define package-level symbols that contain S4 or reference class objects.

If you call this in a package's .R file:

`delayedAssign("hello", stop("boom"))`

but don't refer to "hello" anywhere, when you run R CMD check on a dependent package you'll see the error.

If the expression needs the methods package (like Context$new()), you'll get an error unless the dependent package itself depends on methods.
2014-03-19 09:49:33 -07:00
Yihui Xie
b8b09adda1 submit shiny 0.9.0 to CRAN 2014-03-18 14:32:46 -05:00
Yihui Xie
07c8f0c4b7 use skipStartupTypeset: true for MathJax config, and call MathJax.Hub.Typeset() later
setTimeout() is necessary for uiOutput(); we need to wait for a short while before typesetting math, otherwise two bad things can happen:

1. a math expression may be rendered twice (static output)
2. it is not rendered at all (dynamic ui output)

so the compromise is to typeset math after a short while when the document is ready; 200 ms is an arbitrary choice here
2014-03-18 14:24:23 -05:00
Joe Cheng
2bd201de63 Refactor server logic into separate file 2014-03-17 16:08:59 -07:00
Joe Cheng
0b7e118a37 Merge branch 'staticdocs-0.9.0' into v0.10
Conflicts:
	staticdocs/index.r
2014-03-17 14:40:45 -07:00
Joe Cheng
a546769225 Use new staticdocs packaging standards 2014-03-17 14:37:38 -07:00
Joe Cheng
81745f932d Include withMathJax in staticdocs; improve test 2014-03-17 14:07:05 -07:00
Joe Cheng
4415bf31d2 Mention showcase mode and allow-dots in NEWS 2014-03-13 14:33:25 -07:00
Joe Cheng
5c1bcb41d8 Merge pull request #418 from jcheng5/allow-dots
Allow '.' character in input/output IDs

Fixes #358
2014-03-13 14:25:56 -07:00
Joe Cheng
b659c4c2bb Proper escaping of name, value, and type queries 2014-03-13 12:18:21 -07:00
Joe Cheng
65adc8a405 Wrap for= value in double quotes 2014-03-13 10:16:07 -07:00
Joe Cheng
4141f78717 It's important to return values in JS. heh. 2014-03-13 10:13:26 -07:00
Joe Cheng
80cb02d206 Allow '.' character in input/output IDs
I always thought dots and colons were illegal in HTML ID attributes,
but I was wrong. They are legal and because they are commonly used
in identifier names in R, Shiny users often like to use them. Worse,
Shiny gave no warnings when using dots and only a pretty advanced
subset of functionality would NOT work when using dots, causing
everyone to think they were fully supported in Shiny.

This commit ought to bring reality in line with perception. It turns
out that jQuery has an escaping scheme in its queries that allow us
to support dots after all. As long as we are always careful to
surround IDs with $escape when putting them in a query, we'll be in
good shape.

Colons will probably still cause problems at the moment because we
use colons internally to separate input type from input name. But
we've never seen users try to use colon in IDs before, so we can
wait to fix it until that becomes a problem.
2014-03-12 17:39:05 -07:00
Joe Cheng
a5a4510a1e Merge pull request #417 from yihui/bugfix/showcase-escape
fixes #416: use tags$code() to escape the code in showcase mode
2014-03-11 21:09:48 -07:00
Yihui Xie
95c30649d3 fixes #416: use tags$code() to escape the code in showcase mode
and format(..., indent = FALSE) to prevent indentation of <code>
2014-03-11 22:40:16 -05:00
Joe Cheng
8e5cbde08c Change example licenses to MIT 2014-03-11 10:49:32 -07:00
Yihui Xie
6df8632e29 Merge pull request #414 from jcheng5/bugfix/selectize-order
Fix selectize misordering on updateSelectInput
2014-03-11 11:55:26 -05:00
Jonathan
3c1218fff1 Merge pull request #415 from jcheng5/bugfix/showcase-case
Make showcase mode work with .r files
2014-03-11 09:13:04 -07:00
Joe Cheng
69c0414791 Make showcase mode work with .r files 2014-03-11 09:08:20 -07:00
Joe Cheng
d63f83fcbb Fix selectize misordering on updateSelectInput
Repro case at https://gist.github.com/jcheng5/9403917
2014-03-06 18:27:02 -08:00
Joe Cheng
75c3bf0c2f Change version to 0.9.0 2014-03-06 10:20:25 -08:00
Joe Cheng
c9a8ab2389 Merge pull request #411 from yihui/selectize/backspace
Selectize backspace issue
2014-03-05 00:29:44 -08:00
Yihui Xie
2c467c00e1 10px bottom margin for selectize input 2014-03-04 16:53:29 -08:00
Yihui Xie
c63ec5a1f2 update the test for selectInput() accordingly 2014-03-03 12:02:39 -08:00
Yihui Xie
e886558cbb roxygenize 2014-03-03 12:02:39 -08:00
Yihui Xie
8dd6dabe50 add selectize=TRUE to selectInput(), but disable deletion for single input
hopefully this is a good compromise for #404
2014-03-03 12:02:39 -08:00
Joe Cheng
c090c6adf9 Merge pull request #410 from wch/faster-tags-2
Faster tags
2014-02-28 09:43:57 -08:00
Yihui Xie
84da0befcd fixes #306: remove the possible trailing slash under Windows
the cause:

normalize('foo',  '/') => C:/foo
normalize('foo/', '/') => C:/foo/

under Windows. For unix, the trailing slash will always be removed in normalizePath()
2014-02-27 18:17:50 -06:00
Yihui Xie
267751c8b9 we have specified winslash='/' before, so it is impossible that this char is \ 2014-02-27 17:59:14 -06:00
Winston Chang
8add9f7188 Restructure logic and simplify 2014-02-27 16:02:30 -06:00
Yihui Xie
a100b0991b closes #119: we do not have to do this special treatment to the label for sliderInput, and no other inputs do as.character() for their labels
if users pass an HTML() object to the label argument, the HTML will be preserved instead of being escaped
2014-02-25 23:58:59 -06:00
Winston Chang
9ce9c5e535 More tag writing tweaks 2014-02-25 23:16:50 -06:00
Yihui Xie
b2d004ca1a closes #31: try to avoid scientific notation of numbers 2014-02-25 22:58:08 -06:00
Yihui Xie
657d50f9a3 add the missing Readme's and DESCRIPTION's for the examples 2014-02-25 21:18:16 -06:00
Joe Cheng
60e355c4f5 Faster singleton detection 2014-02-25 18:56:47 -08:00
Yihui Xie
adb444a60f the original hello-world example makes little practical sense -- it is unclear what really changed when moving the slider, especially when obs is large (we always see a "bell-shaped" histogram)
let's make the number of bins reactive instead; now it is very clear what the slider really controls

a histogram with different number of bins also serves as a good demo of the property of histograms (small bins --> small variance + large bias)
2014-02-25 20:44:19 -06:00
Yihui Xie
e7e13ff70d document the new features of DataTables in NEWS 2014-02-25 19:48:46 -06:00
Yihui Xie
a1e81db597 roxygenize 2014-02-25 19:25:48 -06:00
Yihui Xie
f23f2ff0a0 the url of selectiz.js is already in Details 2014-02-25 19:25:48 -06:00
Yihui Xie
c1b18098f1 Revert "add selectize=TRUE to selectInput(), instead of adding a separate function selectizeInput(), per suggestion of @jjallaire"
This reverts commit d3115a3bf3 and closes #404
2014-02-25 19:25:33 -06:00
Joe Cheng
31c39592e3 Faster tag rendering 2014-02-25 16:37:54 -08:00
Yihui Xie
82a1dad22a roxygenize 2014-02-25 15:45:59 -06:00
Yihui Xie
1ecec24727 add a callback argument in renderDataTable() so that users can have access to the DT object 2014-02-25 15:44:00 -06:00
Yihui Xie
607841e947 cosmetic changes 2014-02-25 15:42:36 -06:00
Yihui Xie
e234b403ae when the options is null, also show the search boxes 2014-02-25 00:41:57 -06:00
Yihui Xie
80ce7a36f8 make it possible to filter numeric columns based on the specified range of the form "lower,upper" 2014-02-24 23:59:12 -06:00
Yihui Xie
705a8666be iDisplayLength == -1 means "display all data" (#400)
we can use this feature via several ways, e.g.

- renderDataTable(..., options = list(bPaginate = FALSE))
- iDisplayLength = -1
- aLengthMenu = list(c(10, 30, -1), list(10, 30, 'All'))
2014-02-24 23:31:28 -06:00
Yihui Xie
9167905118 respect the bRegex option (as well as bRegex_j for individual columns)
however, this option is not part of the initialization options, so actually users can never use it...

#400
2014-02-24 23:29:10 -06:00
Yihui Xie
bdeb6734d8 data.options is null by default 2014-02-24 21:46:50 -06:00
Yihui Xie
9a7b042594 respect the individual bSearchable_j options in datatables 2014-02-24 21:02:25 -06:00
Winston Chang
7aea256fd8 Use YYYY/MM/DD format only as a fallback 2014-02-24 16:43:49 -06:00
Yihui Xie
857b5e6932 Merge pull request #406 from wch/date-ie8
Add function for handling date strings in IE8
2014-02-24 16:24:35 -06:00
Winston Chang
1a2d675439 Add function for handling date strings in IE8 2014-02-24 16:02:57 -06:00
Yihui Xie
0c749643de Merge pull request #405 from jcheng5/bugfix/ie8-debounce
Fix debounce error in IE8
2014-02-24 15:46:03 -06:00
Winston Chang
09bb1548f9 Fixes for jshint 2014-02-24 15:35:01 -06:00
Joe Cheng
5ffe531844 Fix debounce error in IE8
In the repo https://github.com/rstudio/shiny-testapp/ the test app
called "setinput" threw errors in IE8 due to the debouncer getting
triggered incorrectly. Essentially Debouncer.$invoke was being
called twice without an intervening normalCall or immediateCall,
which caused apply to be called with this.args === null. Upon
careful inspection/debugging it seems like this may be a bug in the
IE8 implementation of setTimeout/clearTimeout:
http://stackoverflow.com/questions/5853571/clarifying-cleartimeout-behavior-in-ie

In any case, the workaround is to check for a null timer id, which
means we tried to clear the timer at least.
2014-02-24 13:14:17 -08:00
Yihui Xie
fab24a3200 httpuv 1.2.3 is in marutter precise ppa now
hopefully this can save some time for travis ci
2014-02-23 11:09:54 -06:00
Yihui Xie
899d5e9d1d spent two hours on this weird issue of disappearing checkboxes and radio buttons, just to find two missing backslashes for <label>
http://api.jquery.com/jQuery/#creating-new-elements
2014-02-22 01:01:49 -06:00
Joe Cheng
ba510884f2 Avoid using browser URL with host of 0.0.0.0
(reviewed by @jmcphers)
2014-02-21 14:58:19 -08:00
Joe Cheng
78e8df8e17 Fix tags$head + renderUI in IE8, which was broken
Repro case: https://github.com/rstudio/shiny-testapp/tree/master/dynamic_singletons

Reviewed by @jmcphers
2014-02-21 10:15:03 -08:00
Yihui Xie
deba1609c3 implement bSearchable for individual columns (#400)
if a column is not searchable, hide its search box
2014-02-20 18:29:44 -06:00
Yihui Xie
88d2425ca3 respect the bFilter option: when it is false, do not show the search boxes 2014-02-20 18:21:36 -06:00
Yihui Xie
7117f9e058 closes #392: options in renderDataTable() can also take a function to return a list 2014-02-20 16:55:44 -06:00
Yihui Xie
c21c407416 a few cosmetic changes
= to <-, and camelCase instead of under_score
2014-02-20 16:44:09 -06:00
Yihui Xie
4b4ad42063 xtable was built from R < 3.0.0 in the official ubuntu repo hence fails to load 2014-02-20 15:09:42 -06:00
Yihui Xie
474d514c7d the httpuv binary is not in the marutter/c2d4u PPA yet
we can wait for a couple of days and revert this commit
2014-02-20 14:48:08 -06:00
Yihui Xie
6239466da8 klutometis/roxygen#191 has been fixed, so no longer need explicit @usage 2014-02-20 14:30:51 -06:00
Yihui Xie
7746d75582 bug fix: when evalOptions is of length 1, toJSON() converts it to a scalar; we need to use I() to make sure it is always a vector so that we can later $.each() 2014-02-20 14:24:51 -06:00
Yihui Xie
642c9ded08 install some R package dependencies through apt-get instead of R to save time 2014-02-20 13:42:39 -06:00
Joe Cheng
e0ae931ddd Merge pull request #402 from rstudio/bugfix/ie8-compatibility
Bugfix/ie8 compatibility
2014-02-20 10:24:10 -08:00
Jonathan McPherson
0d7727a405 fix Markdown content extraction on IE8 2014-02-20 10:22:43 -08:00
Joe Cheng
28f689498a fix browser height detection and CSS on IE8 2014-02-20 09:16:18 -08:00
Yihui Xie
eb8fec7f2d when searching is turned on, we need to make sure the filtering indices i are smaller than nrow(filtered data) instead of original data
this fixes the bug reported at https://groups.google.com/forum/#!topic/shiny-discuss/xk2Gh7KJQBM
2014-02-19 23:09:25 -06:00
Yihui Xie
2e16fa1d70 fixes #401: pass numbers as character strings in updateNumericInput() to preserver numeric precision when possible 2014-02-19 22:11:39 -06:00
Jonathan McPherson
1b856c4909 use IE8-compatible events; turn off highlighting in IE8 2014-02-19 16:45:58 -08:00
Jonathan
585ad30af1 Merge pull request #396 from jcheng5/bugfix/395-monospace-fonts-qt
Fix issue #395: Monospace fonts broken on QtWebKit
2014-02-19 16:32:38 -08:00
Joe Cheng
c0cdc4083c Merge pull request #397 from yihui/select2
Selectize.js
2014-02-19 15:45:56 -08:00
Joe Cheng
9b9db4f161 Merge pull request #398 from jcheng5/feature/suppress-tag-indent
Add indent argument to format.shiny.tag
2014-02-19 15:21:51 -08:00
Joe Cheng
84a1d8d25e Add comment about format.shiny.tag's indent param 2014-02-19 15:21:28 -08:00
Yihui Xie
d3115a3bf3 add selectize=TRUE to selectInput(), instead of adding a separate function selectizeInput(), per suggestion of @jjallaire 2014-02-19 12:04:23 -06:00
Yihui Xie
964789e9a6 add a note in the NEWS that DataTables also works for IE8 now 2014-02-19 11:58:34 -06:00
Yihui Xie
eeded51ff8 IE8 does not have map() and forEach() methods
use $.each() and $.map() instead
2014-02-19 11:58:34 -06:00
Yihui Xie
8f24f1b4d6 localize es5-shim.js 2014-02-19 11:58:34 -06:00
Yihui Xie
ad910a295a For IE8, $.text() does not work on <script>, so use $.html() instead 2014-02-19 11:58:34 -06:00
Yihui Xie
cf14c6b1e9 add es5-shim.js for IE8 2014-02-19 11:58:34 -06:00
Yihui Xie
49da114caa add a note about the I() options in selectizeInput() 2014-02-19 11:58:34 -06:00
Yihui Xie
b8376ebbf7 it is safer to evaluate the string inside ()
e.g. one cannot directly evaluate {a: 1, b: 2}, although it is legitimate JSON; eval("({a: 1, b: 2})") always works
2014-02-19 11:58:33 -06:00
Yihui Xie
29701d7295 apply checkAsIs() to selectizeInput(), and store the names in data-eval in the script
note we switched the order of {} and config.text() in $.extend(), so that users can overwrite the default options like labelField, valueField, ...
2014-02-19 11:58:33 -06:00
Yihui Xie
16279695a9 factor out the code to determine which options should be evaluated into a utility function checkAsIs(), so that it can be applied to selectizeInput() as well 2014-02-19 11:58:33 -06:00
Yihui Xie
999fc86bc6 news for selectizeInput() 2014-02-19 11:58:33 -06:00
Yihui Xie
0276d533fb the search field must be renamed accordingly 2014-02-19 11:58:33 -06:00
Yihui Xie
b77fc34a7b new function selectizeInput() to use selectize.js
closes #287
2014-02-18 23:25:25 -06:00
Joe Cheng
60c450d57e Add indent argument to format.shiny.tag 2014-02-18 12:55:11 -08:00
Joe Cheng
73411c75db Fix staticdocs test on Linux 2014-02-18 12:52:59 -08:00
Yihui Xie
8d146f7dff Revert "math expressions may come in through renderUI()/uiOutput(), in which case we have to re-typeset the math expressions"
This reverts commit 58471c6971.
2014-02-17 18:52:25 -06:00
Yihui Xie
5c34aa0bb5 remove includeMathJax() and use withMathJax() instead, per suggestion of @jcheng5 2014-02-17 18:52:25 -06:00
Joe Cheng
2b2ed8162d Staticdocs prefers lower-case .r on linux 2014-02-17 16:40:08 -08:00
Joe Cheng
9770bd8005 Tweak two Rd titles 2014-02-17 16:01:57 -08:00
Yihui Xie
4e020818ae white spaces 2014-02-17 14:43:33 -06:00
Yihui Xie
58471c6971 math expressions may come in through renderUI()/uiOutput(), in which case we have to re-typeset the math expressions 2014-02-17 14:43:33 -06:00
Joe Cheng
2a2e02bf56 Remove border radius on showcase well 2014-02-17 11:34:07 -08:00
Joe Cheng
75d8cee766 Fix issue #395: Monospace fonts broken on QtWebKit 2014-02-17 11:31:39 -08:00
Joe Cheng
1aed36bd16 Revert "Merge pull request #298 from jcheng5/remove-catools"
This reverts commit 0ad9a5f9c6, reversing
changes made to c31d91668a.
2014-02-14 13:35:41 -08:00
Joe Cheng
00ce58ed18 Merge pull request #390 from dmbates/patch-2
Update server.R
2014-02-12 13:50:49 -08:00
Douglas Bates
d11aa1a61c Update server.R
Minor typo
2014-02-12 15:25:30 -06:00
Yihui Xie
56a62d3b4d Merge pull request #356 from yihui/feature/datatables-options
To be able to evaluate options passed to DataTables
2014-02-11 23:19:13 -06:00
Yihui Xie
e6dd668657 news for #356 2014-02-11 23:18:32 -06:00
Yihui Xie
f60a64c8db instead of assuming fnFooBar should be evaluated, let's use I() explicitly 2014-02-11 23:12:19 -06:00
Yihui Xie
eff1c298c9 it is okay to include README.md in an R package on CRAN now 2014-02-11 22:59:37 -06:00
Yihui Xie
358b0a122b ignore staticdocs/ when building the source package 2014-02-11 22:59:37 -06:00
Yihui Xie
c0f7ba9d46 use Rd2roxygen to convert the two manually written Rd files to roxygen comments, so that all Rd files are automatically generated from roxygen2 now 2014-02-11 22:59:37 -06:00
Yihui Xie
c4edae8196 using roxygen2 4.0.0: the spurious changes are due to klutometis/roxygen#184 (text in Rd is no longer wrapped by default) 2014-02-11 22:59:37 -06:00
Yihui Xie
398dab808c use @include to make sure the Collate field is correctly generated 2014-02-11 22:59:37 -06:00
Yihui Xie
3530871560 strip white spaces 2014-02-11 22:59:37 -06:00
Yihui Xie
1ba26fdb98 tweak news 2014-02-11 22:31:21 -06:00
Joe Cheng
a3b85b4e3e Add index entry for absolutePanel 2014-02-11 14:19:04 -08:00
Joe Cheng
e37a5d0394 Merge remote-tracking branch 'jcheng5/feature/absolute-panel'
Conflicts:
	NEWS
	man/validateCssUnit.Rd
2014-02-11 14:17:58 -08:00
Yihui Xie
e5a8e77e2a Merge pull request #364 from yihui/feature/mathjax
closes #25: a new function includeMathJax()
2014-02-11 16:06:48 -06:00
Yihui Xie
314b59798f a news item for includeMathjax() 2014-02-11 16:06:20 -06:00
Yihui Xie
e9ae16e534 closes #25: a new function includeMathJax() 2014-02-11 15:59:23 -06:00
Joe Cheng
c971ca0ce2 Merge pull request #388 from rstudio/feature/example-display-mode
Allow display.mode to be provided for examples
2014-02-11 12:45:11 -08:00
Joe Cheng
0ad9a5f9c6 Merge pull request #298 from jcheng5/remove-catools
Remove caTools dependency
2014-02-11 12:40:09 -08:00
Joe Cheng
c31d91668a Suppress staticdocs test when run on a built package 2014-02-10 11:58:40 -08:00
Jonathan McPherson
f5c196d717 allow display.mode to be provided for examples 2014-02-10 10:40:34 -08:00
Joe Cheng
3b90eed89f Add check for staticdocs index correctness 2014-02-05 13:45:25 -08:00
Joe Cheng
9828c8b787 Minor doc tweaks
- Combine sliderInput and animationOptions topics
- Provide better staticdoc index descriptions

Sorry for the big diff, that's due to using a newer version of roxygen.
2014-02-05 13:23:57 -08:00
Winston Chang
b3e997134f Merge branch 'bugfix/381-sendOutputHiddenState' 2014-02-05 12:30:39 -06:00
Winston Chang
f560baa69b Add comments about debouncing 2014-02-05 12:30:25 -06:00
Winston Chang
8cf5f00c87 Remove console logging code 2014-02-05 12:12:38 -06:00
Winston Chang
482c3895d3 Udpate to jQuery 1.11.0
This makes the following JS console message (as noted in #271) go away:
event.returnValue is deprecated. Please use the standard event.preventDefault() instead.
2014-02-05 12:07:28 -06:00
Joe Cheng
fc0d4bde35 Staticdocs index info 2014-02-04 16:13:37 -08:00
Joe Cheng
33ed89a036 Merge pull request #363 from yihui/text-output-container
fixes #90: textOuput() can be put in any tag now
2014-02-03 16:44:08 -08:00
Joe Cheng
0a5953c104 Remove caTools dependency 2014-02-03 16:41:28 -08:00
Joe Cheng
77f6be1a8b Fix URL for slider number format details
Fixes issue #384
2014-02-03 16:37:22 -08:00
Yihui Xie
5bd3f9a571 just to avoid the spurious warning in R CMD check "doRenderTags: no visible binding for global variable 'htmlResult'" 2014-01-30 21:27:43 -06:00
Yihui Xie
ef59119663 Merge pull request #383 from jcheng5/bugfix/broken-image
Don't show broken image when plot is empty
2014-01-30 19:09:08 -08:00
Joe Cheng
45baca7018 Don't show broken image when plot is empty
Repro case:

shiny::runApp(list(
  ui=basicPage(plotOutput('foo')),
  server=function(input, output, session) {
    output$foo <- renderPlot({})
  }
))
2014-01-30 16:46:07 -08:00
Joe Cheng
9b1edb7a97 Fix issue #381: sendOutputHiddenState is called too many times 2014-01-30 10:18:43 -08:00
Yihui Xie
31c071d086 use values instead of names for radioButtons due to #340
the problem was revealed from #377
2014-01-27 22:55:37 -06:00
Joe Cheng
ecf4c5c104 Merge pull request #376 from wch/singleton
Add exports.renderHtml function
2014-01-22 14:35:23 -08:00
Winston Chang
35fbfece0d Export renderHtml function and un-export singletons object 2014-01-21 13:14:21 -06:00
Winston Chang
b7721e42d3 Fixes for jshint 2014-01-21 10:19:50 -06:00
Winston Chang
386346cee9 Add new object for handling singletons 2014-01-21 10:19:50 -06:00
Winston Chang
bbecccc45e Missing semicolon 2014-01-21 10:02:52 -06:00
Yihui Xie
1a8f84c134 and reactive({}) also works; closes #366 2014-01-17 22:41:00 -06:00
Yihui Xie
66181fdcdf reactive(NULL) works now 2014-01-17 22:40:13 -06:00
Winston Chang
b9c05e8a9c Bind both mouse and touch events for jslider
This brings in commit 468002a for jslider. It fixes the problem where
dragging the slider didn't work in the RStudio viewer pane.
2014-01-17 09:36:31 -06:00
Joe Cheng
9c22d6c12a Merge pull request #371 from trestletech/no-write-closed
Don't attempt to write if the connection is closed.
2014-01-16 16:41:23 -08:00
trestletech
f3cedbbd6f Don't attempt to write if the connection is closed. 2014-01-16 14:34:55 -06:00
Joe Cheng
3f3a660ca1 Merge pull request #369 from trestletech/input-handler-patch
Define a non-S3 input registry.
2014-01-16 11:37:28 -08:00
Joe Cheng
1c6ded8416 Merge pull request #370 from trestletech/flush-on-session-end
Flush react/output onSessionEnd
2014-01-16 11:13:16 -08:00
trestletech
aa63fdb26f Flush react/output onSessionEnd 2014-01-16 12:26:29 -06:00
trestletech
3932330ce6 Added tests, stop converting NULLs to NA. 2014-01-15 14:24:13 -06:00
trestletech
3b946b1c69 Removed deprecated function documentation. 2014-01-14 21:26:04 -06:00
trestletech
14df829f18 Update inputHandler docs, revamped tests. 2014-01-14 21:19:12 -06:00
trestletech
788d024be6 Define a non-S3 input registry.
Revises the approach taken in #233.

!! No longer casts NULLs in incoming JSON to NA.
2014-01-14 18:02:19 -06:00
Joe Cheng
c20b56e089 Merge pull request #367 from jcheng5/bugfix/dynamic-singleton
Better handling of dynamically generated singletons
2014-01-14 10:41:10 -08:00
Joe Cheng
287f4f239e Better handling of dynamically generated singletons
Ref:
https://groups.google.com/d/msg/shiny-discuss/cgSHsM1FCjY/vgU1-jmkGjkJ

The user reported that on a page with multiple uiOutputs whose corresponding
renderUI calls all returned sliderInputs (but no sliderInput was present in
ui.R), some but not all of the sliders were initialized correctly; the ones
that were not didn't receive the jquery-slider treatment and just looked like
text boxes.

This was caused by a fundamental flaw in our handling of singletons in
renderUI. The implicit assumption in the old renderUI code was that:

1) Any HTML we generate in renderUI would be rendered in the client
2) Given multiple calls to renderUI, the HTML we return will be rendered in
   the client in the order that we generated it

Both assumptions are incorrect. #1 would be incorrect in cases where an output
is rendered twice before flushOutput is called (this is possible when using an
observer to modify a reactive input, for example), and #2 is incorrect when
output is flushed with multiple values (very common, and exactly what was
happening to the user scenario linked above).

This commit fixes the problem by deferring singleton-handling for uiOutput to
the client. We don't assume that a singleton has been rendered until right
before we render it. The implementation uses a surroundSingletons function on
the server side to surround all singletons with <!--SHINY.SINGLETON[sig]-->
and <!--/SHINY.SINGLETON[sig]-->, which will then be parsed and removed in
the htmlOutputBinding in shiny.js. (And because singletons may contain <head>
elements, we also need to defer <head> hoisting to htmlOutputBinding as well.)

The context$filter mechanism previously used in tagWrite was not flexible
enough to handle this kind of singleton processing. The new rewriteTags
function does tag walking and rewriting much more robustly and flexibly than
context$filter, so I also refactored renderTags to use it instead.

One unrelated problem I noticed was that singleton only worked reliably on
tags, possibly on characters and definitely not on list() or tagList(). This
is because list flattening was happening at tag construction time, which
can cause singleton objects to be trampled. (Among other reasons, such as
context$filter not being called on list objects.) I changed tags.R to not do
any flattening or NULL dropping at tag construction time, but instead to do
it at the last minute during tagWrite.
2014-01-13 17:04:30 -08:00
Joe Cheng
dce66945ec Merge pull request #340 from yihui/bug/null-choices
fix the bug when choices=NULL in updateCheckboxGroupInput()
2014-01-11 13:43:05 -08:00
Yihui Xie
92bd1d5200 Merge pull request #360 from jcheng5/bugfix/359-factors-as-numbers
Fix issue #359: Factors in HTML attributes are being converted to their numeric, not character, equivalent
2014-01-10 19:30:33 -08:00
Yihui Xie
06d2df8211 fixes #90: textOuput() can be put in any tag now
for the example, we use <span>, which is allowed in <h3>
2014-01-10 20:54:28 -06:00
Joe Cheng
36256856b5 Fix issue #359: Factors in HTML attributes are being converted to their numeric, not character, equivalent
This bug was introduced in 3fc1410. Essentially it boils down to the difference between stringifying a factor, and stringifying a list containing a factor:

> as.character(factor('a'))
[1] "a"
> as.character(list(factor('a')))
[1] "1"
The call to split that was introduced in this commit ends up generating lists of factors, not vectors of them.

The best fix I could find was to convert all the attribute values to character before doing the split.
2014-01-10 01:48:02 -08:00
Joe Cheng
a771ae853c Remove extraneous library calls 2014-01-09 10:44:50 -08:00
Yihui Xie
ef4e10bbb1 Merge pull request #355 from jcheng5/bugfix/null-children
Ignore NULL tag elements
2014-01-08 18:51:20 -08:00
Yihui Xie
0dbe4d936e cosmetic changes, just because Github is not aware of my new commits for the PR after it was down 2014-01-08 16:23:23 -06:00
Yihui Xie
731fee11d4 a missing space 2014-01-08 15:54:05 -06:00
Yihui Xie
6759df52c3 show the log files after R CMD check failures 2014-01-08 15:18:01 -06:00
Yihui Xie
914b997076 need to run roxygen2 2014-01-08 15:18:01 -06:00
Yihui Xie
0b8a2fea72 and a missing ) 2014-01-08 14:47:40 -06:00
Yihui Xie
fb2538135c an extra ) 2014-01-08 14:46:57 -06:00
Yihui Xie
b4c547c278 move assignments out, per suggestion of @hadley 2014-01-08 14:22:38 -06:00
Yihui Xie
b243bc846b also include input ID in the warning message, per suggestion of @jcheng5 2014-01-08 14:21:41 -06:00
Joe Cheng
6b8f6162b6 Unify jqueryui copies 2014-01-08 09:41:38 -08:00
Joe Cheng
158db1532b Merge remote-tracking branch 'origin/master' into feature/absolute-panel
Conflicts:
	DESCRIPTION
2014-01-08 09:32:14 -08:00
Jonathan
6abfdb59c6 Merge pull request #352 from rstudio/feature/showcase-mode
Add Shiny Showcase mode
2014-01-08 09:11:24 -08:00
Jonathan McPherson
009d1f9ced make runApp arg take precedence over DESCRIPTION for setting showcase mode 2014-01-08 08:55:30 -08:00
Yihui Xie
555fba6598 Merge pull request #348 from rstudio/feature/navbar-input-binding
add id parameter to navbarPage (support for tab input binding)
2014-01-07 20:47:44 -08:00
Jonathan McPherson
f9017b72a7 remove extraneous parameter to startAppDir 2014-01-07 16:17:16 -08:00
Joe Cheng
99c3c2fc80 Ignore NULL tag elements
We already do the right thing for NULL tag attributes
2014-01-07 15:59:42 -08:00
Jonathan McPherson
32381679f2 update display.mode parameter and width for inputs 2014-01-07 15:50:43 -08:00
Jonathan McPherson
3d031265d1 satisfy R CMD CHECK: validate srcfile, use with(tags rather than withTags 2014-01-07 12:51:03 -08:00
Jonathan McPherson
026cda0071 change DESCRIPTION Type field from ShinyShowcase to Shiny 2014-01-07 11:16:46 -08:00
Jonathan McPherson
fb41ed5a86 make display.mode symmetric with DisplayMode in DESCRIPTION 2014-01-06 15:56:53 -08:00
Jonathan McPherson
8a08468a73 improve code density and zoomed display of inputs 2014-01-06 14:45:05 -08:00
Jonathan McPherson
f600cb4f2c allow source highlighting in files other than server.R 2014-01-06 14:33:31 -08:00
Jonathan McPherson
f754f028dc simplify showcase mode setting in DESCRIPTION 2014-01-06 13:43:02 -08:00
Jonathan McPherson
41b292b45b complete refactoring of raw text output to tags$... methods 2014-01-06 13:19:07 -08:00
Jonathan McPherson
af9be9cae8 use tags functions for writing app info block 2014-01-06 11:03:53 -08:00
Jonathan McPherson
ccfaea64c5 simplify & clean up construction of markdown content 2014-01-06 10:38:05 -08:00
Yihui Xie
a86fc96730 yes, it is weird to select by names instead of values; now the weirdness has gone 2013-12-31 17:03:43 -06:00
Yihui Xie
cf51af17fd news for #340 2013-12-31 16:50:07 -06:00
Yihui Xie
8c1b6a5cf0 update JS tests accordingly
note that getState() no longer includes state.options.selected/checked, which is actually redundant since there is state.value
2013-12-31 16:49:48 -06:00
Yihui Xie
bcecb8cd76 roxygenize 2013-12-31 16:48:17 -06:00
Yihui Xie
557790b0e5 selected refers to values instead of labels/names of choices
added validateSelected() for backward compatibility
2013-12-31 16:48:04 -06:00
Yihui Xie
8eb5a45718 per suggestion of @wch, we do not pass the selected/checked status in the message; the selected values are in message$value, and they will be set via this.setValue(el, data.value) in receiveMessage() in shiny.js
also note that updateSelectInput() is essentially the same as updateCheckboxGroupInput() now, because it does not matter if the attribute name is 'selected' or 'checked'
2013-12-31 15:06:17 -06:00
Yihui Xie
7b64cef73b fixes #176: the problem of choices=NULL also affects selectInput() 2013-12-31 15:06:17 -06:00
Yihui Xie
106203170e pass the selected value(s) to checkbox/radio group 2013-12-31 15:06:17 -06:00
Yihui Xie
174d2bfc11 only do mapply() when length(choices) > 0, otherwise options = list(), and this will lead to an empty checkbox/radio group 2013-12-31 15:06:17 -06:00
Yihui Xie
abda9c7f97 it is not possible to do names(NULL) <- value, so return early when choices is NULL
https://groups.google.com/forum/?pli=1#!topic/shiny-discuss/K7chwrMCvkU
2013-12-31 15:06:17 -06:00
Yihui Xie
8e95260df9 for select input, setValue() with a nonexistent value turns its value to null 2013-12-31 15:05:22 -06:00
Jonathan McPherson
5af1ae1920 reflow comments (and a handful of code lines) to 65 characters 2013-12-30 15:18:21 -08:00
Jonathan McPherson
f0eb9d48c9 show license beneath code 2013-12-30 14:31:45 -08:00
Jonathan McPherson
0ac284009e add Readme.md files to most examples 2013-12-30 13:05:54 -08:00
Winston Chang
fcf963639e Update to Cairo 1.5-5
This version of Cairo properly uses the res argument, so it works with
resolutions higher than 72.
2013-12-27 21:41:34 -06:00
JJ Allaire
ba8c0fb1d5 change name of app start hook to be more consistent with app stop hook 2013-12-26 19:01:45 -05:00
JJ Allaire
08fe74675b update docs on updateTabsetPanel to reflect it's applicablity to navbarPage and navlistPanel 2013-12-25 15:16:52 -05:00
JJ Allaire
f5e7fdf8aa simplify handling of nested menus in tabInputBinding 2013-12-25 15:16:13 -05:00
Joe Cheng
f6e447d049 Merge pull request #349 from rstudio/feature/run-hook
add application run and stop hooks
2013-12-24 09:54:14 -08:00
JJ Allaire
531b21c012 add application run and stop hooks 2013-12-24 10:40:10 -05:00
JJ Allaire
a057456d5a add docs for icon argument to navbarMenu 2013-12-24 09:31:24 -05:00
JJ Allaire
0f043b39f5 add id parameter to navbarPage (support for tab input binding) 2013-12-24 09:12:41 -05:00
Jonathan McPherson
dc0701e21d update DESCRIPTION files and a Readme; tweak spacing 2013-12-23 16:23:33 -08:00
Jonathan McPherson
712f18f4e8 clean up some comments and accidentally introduced whitespace changes 2013-12-23 15:04:05 -08:00
Jonathan McPherson
e0a82b4aaf Merge remote-tracking branch 'origin/master' into feature/showcase-mode 2013-12-23 14:46:48 -08:00
JJ Allaire
a7f238ae0b use correct selector for navbar menu auto-collapse 2013-12-21 17:44:07 -05:00
Yihui Xie
0d99b6de7a Merge pull request #345 from jcheng5/print-html
Nicer printing of HTML tags at console
2013-12-21 11:51:20 -08:00
Joe Cheng
6f627fca96 Minor doc tweak 2013-12-21 11:01:10 -08:00
Joe Cheng
339fbc482b Smarter cursor choosing for absolutePanel 2013-12-21 10:53:23 -08:00
Joe Cheng
72e3ee1d77 Nicer printing of HTML tags at console 2013-12-21 10:26:45 -08:00
Joe Cheng
a9750fb088 Add absolutePanel and fixedPanel (and jquery-ui)
jQueryUI is needed for draggable functionality.
2013-12-20 14:53:11 -08:00
JJ Allaire
d80e3b0824 don't auto-hide when collapased navbar submenu is clicked 2013-12-20 17:06:42 -05:00
Jonathan McPherson
46df7a9ea0 make jshint happy (avoid leaking globals) 2013-12-20 12:23:05 -08:00
Joe Cheng
b851ce49f7 Forgot to roxygenize a previous doc change 2013-12-20 11:54:22 -08:00
Winston Chang
d9afde3e15 Merge pull request #342 from trestletech/master
Unlist dates to properly handle date ranges.
2013-12-19 20:34:43 -08:00
trestletech
b38c57f308 Unlist dates to properly handle date ranges. 2013-12-19 17:58:17 -06:00
Jonathan McPherson
93e7e2e06e set height of code window based on height of surrounding window 2013-12-19 15:08:27 -08:00
Jonathan McPherson
5ac09180a5 don't emit superfluous newline at beginning of .R files 2013-12-19 14:03:07 -08:00
JJ Allaire
3819ca3a62 add descriptions for examples 2013-12-19 16:59:26 -05:00
Jonathan McPherson
00426b4c9b fix incorrect character accounting with newlines 2013-12-19 13:39:36 -08:00
Jonathan McPherson
58d8cefcc0 set sxs mode on load if browser is wide enough 2013-12-19 12:51:08 -08:00
Jonathan McPherson
c8bb122557 hide entire well when app doens't have metadata in sxs mode 2013-12-19 12:21:17 -08:00
Jonathan McPherson
bcef603a36 new layout: remove top bar, show app info by readme 2013-12-19 11:35:27 -08:00
Jonathan McPherson
639b4d392a coerce strings from DESCRIPTION to correct types 2013-12-19 10:18:57 -08:00
Jonathan McPherson
6d5f06a61d initial support for showcase mode from DESCRIPTION (not complete) 2013-12-18 17:06:31 -08:00
Jonathan McPherson
3e00e2ad58 show contents of global.R if it exists 2013-12-18 15:13:11 -08:00
Jonathan McPherson
cad2be5e53 always use tabs to show code; show readme alongside code 2013-12-18 13:41:15 -08:00
Jonathan McPherson
58fe5f263f nicer code tabs in code-alongside mode 2013-12-17 20:18:22 -08:00
Jonathan McPherson
79ec6845f8 use more bootstrap-flavored styles 2013-12-17 16:10:53 -08:00
Jonathan McPherson
0f81ba8307 use minified jquery ui 2013-12-17 15:09:26 -08:00
Jonathan McPherson
a30543b035 use rstudio fork of highlight.js 2013-12-17 14:51:44 -08:00
Jonathan McPherson
5c4473a1d9 use side-by-side code and app instead of a popup window 2013-12-17 14:07:22 -08:00
Jonathan McPherson
7ff47c8c51 use rstudio default highlight colors 2013-12-17 13:52:17 -08:00
Jonathan McPherson
2544e29be3 use show with app / show below buttons to toggle 2013-12-17 13:16:23 -08:00
Jonathan McPherson
d7bf564e8f make initial transition a little smoother 2013-12-17 11:15:11 -08:00
Jonathan McPherson
0f135f881a make code position toggleable 2013-12-17 10:56:40 -08:00
Jonathan McPherson
2f1bb5e1c0 begin restricting code height and scrolling relevant portion into view 2013-12-17 10:23:27 -08:00
Jonathan McPherson
02b5f96eee move from popup window model to side-by-side model 2013-12-17 09:00:27 -08:00
JJ Allaire
3e77871539 move shinyapps gitignore to root 2013-12-16 17:38:57 -05:00
Jonathan McPherson
676affdd03 add new header-free showcase mode (use showcase=2 on query string) 2013-12-16 14:12:13 -08:00
Jonathan McPherson
5caf41c067 Merge remote-tracking branch 'origin/master' into feature/showcase-mode 2013-12-16 13:21:59 -08:00
Jonathan McPherson
58f9e89fab restore javascript markdown formatter 2013-12-16 13:15:11 -08:00
JJ Allaire
8776f0f4a5 Merge branch 'feature/showcase-mode' of github.com:rstudio/shiny into feature/showcase-mode 2013-12-16 15:19:47 -05:00
JJ Allaire
84a8c27926 gitignore for artifacts of deploying to shinyapps 2013-12-16 15:17:13 -05:00
Jonathan McPherson
f061e3486e move showcase-specific css to its own file 2013-12-16 09:52:58 -08:00
Jonathan McPherson
da23995343 make jshint happy 2013-12-16 09:35:31 -08:00
Yihui Xie
4e0a61bd9b Merge pull request #319 from jcheng5/feature/console-reactivity
Features for easier explaining of reactivity
2013-12-16 09:28:14 -08:00
Yihui Xie
d3e2fa5df5 Merge pull request #336 from jcheng5/bugfix/335-singleton-observer
Fix #335: Singleton observer shows up in reactlog
2013-12-16 09:25:50 -08:00
Joe Cheng
00b111c974 Merge remote-tracking branch 'origin/master' into feature/console-reactivity
Conflicts:
	NAMESPACE
	NEWS
2013-12-16 09:25:45 -08:00
Jonathan McPherson
bd265c00a0 add documentation for showcase mode parameter to runApp 2013-12-16 09:25:02 -08:00
Joe Cheng
ef53a63766 Merge pull request #327 from rstudio/feature/bootstrap-layout
fluidPage and fixedPage and related bootstrap layout functions
2013-12-16 09:18:35 -08:00
JJ Allaire
688c7f1a1c improve docs on theme parameter 2013-12-16 12:01:22 -05:00
Winston Chang
2989922253 Bump Cairo to 1.5-4
This is to avoid a bug in 1.5-3, where plots wouldn't appear properly.
2013-12-16 10:36:12 -06:00
JJ Allaire
6f6619a5ab Add type parameter to tabsetPanel to enable the use of pill style tabs 2013-12-16 10:20:34 -05:00
JJ Allaire
1594c228e8 re-roxygenize 2013-12-16 10:18:08 -05:00
JJ Allaire
fb44f52aa9 add navlistPanel function 2013-12-16 10:09:38 -05:00
JJ Allaire
045ead1728 re-roxygenzie 2013-12-16 09:58:31 -05:00
JJ Allaire
4404463e53 tweak news linebreak 2013-12-16 08:27:15 -05:00
JJ Allaire
b79b61c8c8 merge from master
Merge remote-tracking branch 'origin/master' into feature/bootstrap-layout

Conflicts:
	NEWS
	R/bootstrap.R
2013-12-16 08:26:22 -05:00
Joe Cheng
467048a0fc Fix erroneous comments in 03_reactivity 2013-12-15 15:15:16 -08:00
Joe Cheng
2a1edffce3 Fix #335: Singleton observer shows up in reactlog 2013-12-15 01:00:16 -08:00
Joe Cheng
ce833c39d5 setAutoflush refactor for clarity 2013-12-15 00:21:49 -08:00
Joe Cheng
721a74eee6 Fix example 2013-12-14 23:35:32 -08:00
Joe Cheng
8f9f4f894c Incorporate code review feedback from @yihui 2013-12-14 23:35:32 -08:00
Joe Cheng
842765dad0 Features for easier explaining of reactivity
- makeReactiveBinding: Turns a "regular" variable into a reactive.
  No need to use reactiveValues() for simple reactivity.
- setAutoflush (not exported): Causes flushReact() to be called
  each time something is executed at the R console top-level.
- options(shiny.suppressMissingContextError=TRUE): Prevents the
  "Operation not allowed without an active reactive context" error
  when attempting to read a reactive value or expression from the
  console.
2013-12-14 23:35:32 -08:00
Joe Cheng
b23cc47d95 Merge pull request #334 from rstudio/feature/font-awesome
icon function for embedding icons from the font-awesome icon library
2013-12-14 21:47:52 -08:00
JJ Allaire
85baa596d0 remove widths parameter from columnLayout; add width parameter to sidebarPanel and mainPanel 2013-12-14 17:26:08 -05:00
JJ Allaire
e371fff110 update NEWS 2013-12-14 10:17:33 -05:00
JJ Allaire
dffe6b4f39 Merge remote-tracking branch 'origin/master' into feature/font-awesome 2013-12-14 09:46:59 -05:00
JJ Allaire
dbf684f385 merge origin/master 2013-12-14 09:46:37 -05:00
JJ Allaire
7b20fd91ef fix R CMD check documentation errors 2013-12-14 09:44:54 -05:00
JJ Allaire
300c25ded1 re-roxygenize 2013-12-14 09:07:37 -05:00
JJ Allaire
284e814d2a integrate icons into the rest of the ui 2013-12-14 09:02:11 -05:00
Jonathan McPherson
d5cdaddeea use markdown package instead of client-side md renderer 2013-12-13 16:15:10 -08:00
JJ Allaire
8635b395a1 Merge remote-tracking branch 'origin/master' into feature/bootstrap-layout 2013-12-13 17:55:59 -05:00
Jonathan McPherson
c2cf4e72f8 decouple showcase mode from app boot; factor out of shiny.js 2013-12-13 14:46:31 -08:00
Yihui Xie
92def0f71d Merge pull request #332 from jcheng5/bugfix/no-html-class
Fix test breakage due to HTML() missing from rendered output
2013-12-13 14:27:36 -08:00
Joe Cheng
bccae9d71c Fix test breakage due to HTML() missing from rendered output 2013-12-13 14:18:06 -08:00
JJ Allaire
90b6a2f82b add documentation on host parameter to runExample 2013-12-13 15:59:46 -05:00
JJ Allaire
0462df7de2 fix documentation error in sidebarLayout 2013-12-13 15:57:40 -05:00
JJ Allaire
d4b29ab08d initial font-awesome import 2013-12-13 15:56:18 -05:00
JJ Allaire
09f2dfe181 Merge remote-tracking branch 'origin/master' into feature/bootstrap-layout 2013-12-13 15:47:37 -05:00
Yihui Xie
317d013a0b Merge pull request #330 from yihui/travis
Travis CI
2013-12-13 12:41:04 -08:00
JJ Allaire
e26b2dcd43 refer to application layout guide 2013-12-13 14:37:49 -05:00
JJ Allaire
4676dbc740 update link to component layout guide 2013-12-13 14:33:10 -05:00
JJ Allaire
778f869ddb all functions now work with fluid or fixed layouts 2013-12-13 13:57:37 -05:00
JJ Allaire
a7e9b1f76d eliminate columnLayout (just use fluidRow) 2013-12-13 13:40:36 -05:00
JJ Allaire
096e56aaa8 eliminate horizontalPanel and pull left/right functions 2013-12-13 13:30:52 -05:00
Jonathan McPherson
d1bcc557f0 move showcase js to its own file; fix cross-document bug on firefox 2013-12-13 10:20:50 -08:00
JJ Allaire
e041fab319 Merge remote-tracking branch 'origin/master' into feature/bootstrap-layout 2013-12-13 09:38:48 -05:00
JJ Allaire
3394e36325 cross reference component and grid layout guides from help topics 2013-12-13 09:19:02 -05:00
JJ Allaire
a501458e5a Refer to Bootstrap without Twitter preface; link explicitly to v2.3.2 documentation 2013-12-13 08:24:11 -05:00
JJ Allaire
da08eef5ef add title parameter to top level page functions 2013-12-13 08:19:44 -05:00
JJ Allaire
0ea714552a update examples to use sidebarLayout rather than pageWithSidebar 2013-12-13 07:52:47 -05:00
JJ Allaire
8cba584e52 deprecation notices 2013-12-13 06:32:49 -05:00
JJ Allaire
878f07d2cf tweak docs for theme parameter 2013-12-13 06:29:29 -05:00
Yihui Xie
d297de732f ignore travis.yml in .Rbuildignore 2013-12-13 00:52:46 -06:00
Yihui Xie
c41d4d32b9 enable Travis CI
YAML copied from https://github.com/yihui/highr/blob/master/.travis.yml
2013-12-13 00:31:31 -06:00
JJ Allaire
5d34134888 update NEWS for theme parameter 2013-12-12 22:47:16 -05:00
Jonathan McPherson
f968ec4cac fix node cloning on IE browsers 2013-12-12 17:03:21 -08:00
Jonathan McPherson
fdb256a534 fix some animation and margin problems 2013-12-12 16:16:04 -08:00
Jonathan McPherson
62a2b57613 clarify regions of app UI vs. showcase UI 2013-12-12 15:45:39 -08:00
JJ Allaire
90f5ebfa58 add support for specifying an alternative bootstrap theme 2013-12-12 17:56:07 -05:00
Jonathan McPherson
66aecee519 fix highlighting for text points inside <SPAN>s 2013-12-12 14:02:53 -08:00
JJ Allaire
f0c661d6e2 enable shiny applications to opt out of bootstrap responsive css 2013-12-12 16:23:26 -05:00
JJ Allaire
a27f5b4c15 make default arguments of navbar page header and footer NULL 2013-12-12 15:58:00 -05:00
Jonathan McPherson
95b69f0003 initial support for sending source refs for reactives (not wired) 2013-12-12 12:57:04 -08:00
JJ Allaire
6925f0bf7a remove head paramter from page functions
tags$head can just be included inline as one of the elements passed to the function at the top-level
2013-12-12 15:48:35 -05:00
Jonathan McPherson
6c1a9ed83b add showdown dependency 2013-12-12 12:18:57 -08:00
Jonathan McPherson
3ebef79313 refactor showcase outputs from renderPage 2013-12-12 12:16:01 -08:00
Jonathan McPherson
57393806b0 initial support for Readme.md 2013-12-12 11:47:04 -08:00
JJ Allaire
721d8cfa49 enhance docs 2013-12-12 14:28:21 -05:00
JJ Allaire
9e5b68444f add support for menus on navbars (navbarMenu function) 2013-12-12 13:41:32 -05:00
Jonathan McPherson
9f6c619401 initial support for header generated from DESCRIPTION 2013-12-12 10:28:38 -08:00
Yihui Xie
1b47e40a3a Merge pull request #328 from rstudio/feature/rproj-changes
Rproj changes: don't roxygenize; use --as-cran for test
2013-12-12 09:44:58 -08:00
JJ Allaire
3fc14102e5 concatenate duplicate attributes in tag definitions 2013-12-12 08:41:53 -05:00
JJ Allaire
d907992c39 Automatically concatenate multiple class attributes in tag definitions 2013-12-12 08:06:20 -05:00
JJ Allaire
ae2f35c6c5 Rproj changes: don't roxygenize; use --as-cran for test 2013-12-12 06:20:35 -05:00
JJ Allaire
ddd804041d Rd changes for R CMD check 2013-12-12 06:16:51 -05:00
JJ Allaire
2478cbdb6f prevent long line lengths for links to bootstrap docs 2013-12-12 06:08:29 -05:00
JJ Allaire
80e992a9fc allow pullLeft/Right functions to take tags or lists of tags; validate that all inputs are tags 2013-12-12 06:02:31 -05:00
JJ Allaire
e4b8e08e89 use paste0 where appropriate 2013-12-12 05:51:12 -05:00
Jonathan McPherson
6c556b8a72 improve style and behavior of code popout window 2013-12-11 17:38:02 -08:00
Jonathan McPherson
9659c19b23 initial support for code pop-out 2013-12-11 17:03:27 -08:00
Jonathan McPherson
aa6e9d9bf2 find column by sibling nodes 2013-12-11 15:07:30 -08:00
Jonathan McPherson
812f0ac32c refine source ref location (columns still need work) 2013-12-11 14:06:12 -08:00
Jonathan McPherson
296b312950 scaffolding for flashing executing outputs 2013-12-11 13:22:00 -08:00
JJ Allaire
29a06406ea Merge remote-tracking branch 'origin/master' into feature/bootstrap-layout 2013-12-11 15:47:01 -05:00
JJ Allaire
261cb7d3cd fix incorrect ellipses arg in hr function 2013-12-11 15:46:38 -05:00
JJ Allaire
ba5a57ac07 fix columnLayout function 2013-12-11 13:38:50 -05:00
JJ Allaire
c0ebe9d7a1 allow row functions to take a class 2013-12-11 13:07:35 -05:00
JJ Allaire
2b83012786 update roxygen docs for navbarPage fluid argument 2013-12-11 13:04:59 -05:00
Jonathan McPherson
b9761288bd send reactive log information to the client 2013-12-11 09:48:37 -08:00
JJ Allaire
a711e83398 Merge remote-tracking branch 'origin/master' into feature/bootstrap-layout 2013-12-11 12:43:21 -05:00
Yihui Xie
2705385681 Merge pull request #320 from rstudio/feature/layout-cleanup
misc cleanup of new layout functions
2013-12-11 09:11:42 -08:00
JJ Allaire
4b2f3dd070 merge from master
Merge remote-tracking branch 'origin/master' into feature/bootstrap-layout

Conflicts:
	NAMESPACE
	NEWS
2013-12-11 06:05:22 -05:00
JJ Allaire
876acf2839 Merge remote-tracking branch 'origin/master' into feature/layout-cleanup 2013-12-11 06:00:43 -05:00
JJ Allaire
d0446f068c Merge remote-tracking branch 'origin/master' into feature/layout-cleanup 2013-12-11 05:59:02 -05:00
Yihui Xie
a9396d1e2f Merge pull request #324 from rstudio/feature/hr-tag
add hr tag to exported html builder tags
2013-12-10 21:01:28 -08:00
JJ Allaire
e87102e586 update NEWS 2013-12-10 20:41:17 -05:00
JJ Allaire
8b213f8d7c update NEWS 2013-12-10 20:40:21 -05:00
JJ Allaire
9a7dc5ba86 add hr tag to exported html builder tags 2013-12-10 20:20:16 -05:00
JJ Allaire
9acb3f83f8 add fluid parameter to navbarPage to specify fluid vs. fixed layout 2013-12-10 20:04:57 -05:00
JJ Allaire
1c676211ee more revisions to layout functions -- go back to page level constructs for fixed and fluid 2013-12-10 16:15:17 -05:00
Jonathan McPherson
89728164eb highlight code with highlight.js 2013-12-10 12:11:40 -08:00
Jonathan McPherson
d0c4093f5a use built-in parseQueryString 2013-12-10 10:46:03 -08:00
Jonathan McPherson
d7f680fb19 show ui.R and server.R files in showcase mode 2013-12-10 10:20:50 -08:00
JJ Allaire
48279e060c add validation of layout function inputs 2013-12-10 12:57:56 -05:00
Jonathan McPherson
10dd0d07dc showcase mode stub controlled by showcase=1 parameter 2013-12-10 09:50:51 -08:00
JJ Allaire
d82dc4cf77 introduce more layout functions 2013-12-10 12:02:59 -05:00
JJ Allaire
2b9553e4da refactor functions to use fixed and fluid explicitly and to introduce the notion of "layout" functions 2013-12-10 11:35:56 -05:00
Joe Cheng
ac112ea287 Race condition where clientData$singletons can be NULL
Reproduced in Shiny Server load testing.

Code reviewed by @trestletech
2013-12-09 15:51:45 -08:00
JJ Allaire
4f6b099615 move page functions to the top of the bootstrap-layout file 2013-12-09 16:43:55 -05:00
JJ Allaire
d4dcb162d0 functions for creating lower-level bootstrap layouts 2013-12-09 14:35:49 -05:00
Yihui Xie
46054f513b fixes #314: the data passed to htmlOutputBinding could be null 2013-12-08 17:55:49 -06:00
JJ Allaire
261f67df50 update NAMESPACE For removed panelWithSidebar 2013-12-08 09:14:36 -05:00
JJ Allaire
22f9b2affe rename tabsPosition to position 2013-12-08 09:10:50 -05:00
JJ Allaire
06c392c066 remove panelWithSidebar (this scenario will be handled by more composable top-level pages) 2013-12-08 09:10:28 -05:00
JJ Allaire
3d67b3bc17 Merge branch 'feature/remove-tab-condition' into feature/layout-cleanup 2013-12-08 09:06:47 -05:00
JJ Allaire
6cefab5d8a Merge branch 'feature/navbar-header-footer' into feature/layout-cleanup 2013-12-08 09:06:35 -05:00
JJ Allaire
cc261de37b remove condition attribute from tabPanel
the tab content visibility needs to be the union of data-display-if and whether the tab is active (the currenty implementation makes it always visible when data-display-if evaluates to true)
2013-12-07 17:16:02 -05:00
JJ Allaire
20712641a7 re-roxygenize for tabsetPanel position argument 2013-12-07 17:09:53 -05:00
JJ Allaire
e4d0b16fd5 add header and footer arguments to navbarPage 2013-12-07 17:09:26 -05:00
JJ Allaire
f8c25791e9 Merge pull request #318 from rstudio/feature/tabs-position
Add position parameter to tabsetPanel
2013-12-06 12:31:50 -08:00
JJ Allaire
704aa433d4 use match.arg for tabsPosition 2013-12-06 15:30:23 -05:00
Joe Cheng
3bd1003164 Merge pull request #316 from rstudio/feature/conditional-tabs
conditional expression to determine visibility of tabPanel
2013-12-06 11:21:58 -08:00
JJ Allaire
8dd55d7506 always assign data-display-if (it will be dropped if it's NULL) 2013-12-06 13:04:56 -06:00
Joe Cheng
6252d778c1 Merge pull request #317 from rstudio/feature/head-param
add optional head parameter to top-level page functions
2013-12-06 10:58:26 -08:00
Joe Cheng
942248b9e6 Merge pull request #315 from rstudio/feature/navbar-page
navbarPage and panelWithSidebar
2013-12-06 10:51:07 -08:00
Winston Chang
4793449105 Add example for actionButton 2013-12-06 12:13:31 -06:00
JJ Allaire
428e3bc0fc forward head parameter in pageWithSidebar 2013-12-06 12:09:35 -06:00
Winston Chang
bf2c80cfcf Improvements to invalidateLater docs 2013-12-06 12:09:23 -06:00
JJ Allaire
06b0685a57 change name of position parameter to tabsPosition 2013-12-06 11:33:49 -06:00
JJ Allaire
231ea25968 Add position paramter to tabsetPanel to enable positioning of tabs above, below, left, or right of tab content 2013-12-06 10:34:04 -06:00
JJ Allaire
8658eeddb2 update NEWS 2013-12-06 09:10:38 -06:00
JJ Allaire
d0769eed97 add optional head parameter to top-level page functions 2013-12-06 08:56:20 -06:00
JJ Allaire
b1fcd1f7c8 conditional expression to determine visibility of tabPanel 2013-12-06 08:12:26 -06:00
JJ Allaire
db1259b3e0 docs for collapsable and re-roxygenize 2013-12-05 10:31:03 -06:00
JJ Allaire
1a5f42b753 auto collapse navbar menu on click 2013-12-05 10:12:39 -06:00
JJ Allaire
75d061a7fa support optional collablable navbar 2013-12-05 09:17:57 -06:00
JJ Allaire
9fb4c4140b navbarPage and panelWithSidebar 2013-12-05 07:09:46 -05:00
JJ Allaire
0306877fb9 re-roxygenize for host parameter 2013-12-04 13:07:06 -05:00
Winston Chang
86e3b05a3f Merge pull request #233 from trestletech/input-registry
Create a user-extensible registry of custom Shiny Input handlers.
2013-12-03 14:19:05 -08:00
trestletech
a4e8907c95 Merged rstudio/master into branch. 2013-12-03 15:15:14 -06:00
Yihui Xie
916ad6535a fixes #299: RJSONIO is unable to convert a matrix of 0 row to [], in which case we have to use an empty list() instead
toJSON(list(x = matrix(nrow = 0, ncol = 3))) gives '{\n "x":  \n}', which is an invalid JSON expression
2013-12-03 15:03:39 -06:00
Yihui Xie
c129309937 Merge pull request #310 from yihui/master
closes #277: implement actionButton.setValue()
2013-12-03 12:55:46 -08:00
trestletech
0088e9ae77 Preface shiny input classes with shiny. Refine tests to use S3 dispatch. 2013-11-30 15:19:21 -06:00
Yihui Xie
79806b5ad5 closes #277: implement actionButton.setValue() 2013-11-26 23:51:35 -06:00
Winston Chang
7d59fbfc36 Merge pull request #302 from wch/jshint
Fixes to make JSHint happy
2013-11-22 12:11:07 -08:00
Winston Chang
e645bdf249 Add jshint options to suppress warnings 2013-11-22 13:51:52 -06:00
Winston Chang
0bedf26849 Check for own properties 2013-11-22 13:36:18 -06:00
Winston Chang
a153c5b4ce Change function defs to vars
This makes the scoping clearer.
2013-11-22 13:32:54 -06:00
Winston Chang
44f1f3e9ae Fixes for jshint 2013-11-21 17:07:47 -06:00
Winston Chang
8c82fa86c6 Update NEWS 2013-11-21 16:42:56 -06:00
Winston Chang
d4da934d6a Merge branch 'renderui-head-singleton'
Conflicts:
	NEWS
2013-11-21 16:42:42 -06:00
Winston Chang
56cc664c26 Use === 2013-11-21 16:37:16 -06:00
Joe Cheng
eaa0bdfc62 Merge pull request #278 from yihui/changeset/source
use sys.source() and keep.source=TRUE
2013-11-21 13:34:08 -08:00
Yihui Xie
c538e9c6d4 use globalenv() instead of .Globalenv; remove local() 2013-11-20 18:00:24 -06:00
Winston Chang
54b9af0299 Merge branch 'localhost-only'
Conflicts:
	NEWS
2013-11-20 13:54:47 -06:00
Winston Chang
c7d5b9211c Merge pull request #271 from wch/bootstrap
Update to Bootstrap 2.3.2 and jQuery 1.10.2
2013-11-19 20:15:20 -08:00
Winston Chang
7ca22a8718 Add updated version of jslider
This adds compatibility with jQuery 1.9+
2013-11-19 21:47:39 -06:00
trestletech
4e37b32976 Enumerate function variables, setup Roxygen to pass R CMD CHECK, added tests. 2013-11-19 20:46:51 -06:00
Winston Chang
9725b23db1 Update NEWS 2013-11-19 14:36:21 -06:00
Winston Chang
2e60f2b2ce Update to jQuery 1.10.2 2013-11-19 14:35:53 -06:00
Winston Chang
004776a522 Fix dateinput docs for pt-BR language 2013-11-19 11:19:12 -06:00
Joe Cheng
92fa1dde79 Fix #21: singleton and tags$head are not really compatible with reactiveUI
This commit fixes two problems:

- tags$head content was not properly hoisted into the head
  of the document when UI was reactively rendered
- singletons were not respected in renderUI

This makes it possible for input/output components that rely
on JavaScript libraries to simply put their script/style
dependencies in their input/output methods. This is contrary
to previous versions of Shiny where that approach would work
unless the component only appeared in renderUI/uiOutput and
not as part of the initial page render.
2013-11-09 15:11:22 -08:00
Joe Cheng
464821c4e2 Only allow access via localhost by default
This can be overridden via the "shiny.host" option or by explicitly
passing the host parameter to runApp/runExample.
2013-11-08 23:26:59 -08:00
Joe Cheng
e95483236a Merge pull request #295 from wch/quiet
Add quiet option to runApp
2013-11-08 22:03:42 -08:00
Winston Chang
a9b97a85ad Add quiet option to runApp 2013-11-07 11:26:27 -06:00
Yihui Xie
6170befc90 Merge pull request #289 from wch/methods
Move methods package to Depends
2013-11-01 12:30:39 -07:00
Winston Chang
5ecb85cb6d Bump version to .99 for development 2013-10-30 10:34:50 -05:00
Winston Chang
d2fc04f45d Merge branch 'v0.8.0-rc' 2013-10-30 10:33:27 -05:00
Winston Chang
9f78dbf200 Move methods package to Depends 2013-10-26 12:05:12 -05:00
trestletech
d3e7f130fb Parse incoming NULLs as NA. 2013-10-21 21:33:25 -05:00
trestletech
c0cd269322 Revert "Customize dispatch for NULL objects."
This reverts commit f4ada70e56.
2013-10-21 20:43:02 -05:00
Yihui Xie
a9e4ce005d closes #238: use keep.source() for sys.source() 2013-10-18 22:38:32 -05:00
Yihui Xie
987f2b2a55 closes #236: use sys.source(envir=) instead of source(local=) 2013-10-18 22:19:25 -05:00
trestletech
f4ada70e56 Customize dispatch for NULL objects.
Don't provide class for input objects based on `type` field. Provide real NULLs to dispatched functions rather than empty lists.
2013-10-18 17:27:28 -05:00
trestletech
97e658709d Added S3-dispatched input parsers. 2013-10-18 17:20:24 -05:00
Winston Chang
559c6722ff Update NEWS 2013-10-15 15:24:02 -05:00
Winston Chang
aab2cce978 Update to Bootstrap 2.3.2 2013-10-15 12:13:34 -05:00
Joe Cheng
49a08d14c3 Code review feedback, part 1 2013-06-19 11:39:09 -07:00
Joe Cheng
25990f59d8 Add observeEvent and eventFilter functions for handling events 2013-06-18 18:42:00 -07:00
438 changed files with 75593 additions and 30962 deletions

View File

@@ -1,12 +1,18 @@
^\.Rproj\.user$
^\.git$
^examples$
^README\.md$
^shiny\.Rproj$
^shiny\.sh$
^shiny\.cmd$
^run\.R$
^\.gitignore$
^smoketests$
^res$
^tools$
^man-roxygen$
^\.travis\.yml$
^staticdocs$
^tools$
^srcjs$
^CONTRIBUTING.md$
^cran-comments.md$
^.*\.o$

2
.Rinstignore Normal file
View File

@@ -0,0 +1,2 @@
^tools$
^Rmd$

4
.gitattributes vendored Normal file
View File

@@ -0,0 +1,4 @@
/NEWS merge=union
/inst/www/shared/shiny.js -merge -diff
*.min.js -merge -diff
*.js.map -merge -diff

1
.gitignore vendored
View File

@@ -6,4 +6,5 @@
*.so
/src-i386/
/src-x86_64/
shinyapps/
README.html

15
.travis.yml Normal file
View File

@@ -0,0 +1,15 @@
language: r
warnings_are_errors: true
r_binary_packages:
- Rcpp
- cairo
- knitr
r_github_packages:
- rstudio/htmltools
notifications:
email:
on_success: change
on_failure: change

10
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,10 @@
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](http://www.rstudio.com/wp-content/uploads/2014/06/RStudioIndividualContributorAgreement.pdf) or [corporate](http://www.rstudio.com/wp-content/uploads/2014/06/RStudioCorporateContributorAgreement.pdf) contributor agreement as appropriate. You can send the signed copy to jj@rstudio.com.
3. Submit a [pull request](https://help.github.com/articles/using-pull-requests).
We'll try to be as responsive as possible in reviewing and accepting pull requests. We appreciate your contributions!

View File

@@ -1,51 +1,139 @@
Package: shiny
Type: Package
Title: Web Application Framework for R
Version: 0.8.0
Date: 2013-10-26
Author: RStudio, Inc.
Maintainer: Winston Chang <winston@rstudio.com>
Description: Shiny makes it incredibly easy to build interactive web
Version: 0.13.0
Date: 2016-01-12
Authors@R: c(
person("Winston", "Chang", role = c("aut", "cre"), email = "winston@rstudio.com"),
person("Joe", "Cheng", role = "aut", email = "joe@rstudio.com"),
person("JJ", "Allaire", role = "aut", email = "jj@rstudio.com"),
person("Yihui", "Xie", role = "aut", email = "yihui@rstudio.com"),
person("Jonathan", "McPherson", role = "aut", email = "jonathan@rstudio.com"),
person(family = "RStudio", role = "cph"),
person(family = "jQuery Foundation", role = "cph",
comment = "jQuery library and jQuery UI library"),
person(family = "jQuery contributors", role = c("ctb", "cph"),
comment = "jQuery library; authors listed in inst/www/shared/jquery-AUTHORS.txt"),
person(family = "jQuery UI contributors", role = c("ctb", "cph"),
comment = "jQuery UI library; authors listed in inst/www/shared/jqueryui/1.10.4/AUTHORS.txt"),
person("Mark", "Otto", role = "ctb",
comment = "Bootstrap library"),
person("Jacob", "Thornton", role = "ctb",
comment = "Bootstrap library"),
person(family = "Bootstrap contributors", role = "ctb",
comment = "Bootstrap library"),
person(family = "Twitter, Inc", role = "cph",
comment = "Bootstrap library"),
person("Alexander", "Farkas", role = c("ctb", "cph"),
comment = "html5shiv library"),
person("Scott", "Jehl", role = c("ctb", "cph"),
comment = "Respond.js library"),
person("Stefan", "Petre", role = c("ctb", "cph"),
comment = "Bootstrap-datepicker library"),
person("Andrew", "Rowls", role = c("ctb", "cph"),
comment = "Bootstrap-datepicker library"),
person("Dave", "Gandy", role = c("ctb", "cph"),
comment = "Font-Awesome font"),
person("Brian", "Reavis", role = c("ctb", "cph"),
comment = "selectize.js library"),
person("Kristopher Michael", "Kowal", role = c("ctb", "cph"),
comment = "es5-shim library"),
person(family = "es5-shim contributors", role = c("ctb", "cph"),
comment = "es5-shim library"),
person("Denis", "Ineshin", role = c("ctb", "cph"),
comment = "ion.rangeSlider library"),
person("Sami", "Samhuri", role = c("ctb", "cph"),
comment = "Javascript strftime library"),
person(family = "SpryMedia Limited", role = c("ctb", "cph"),
comment = "DataTables library"),
person("John", "Fraser", role = c("ctb", "cph"),
comment = "showdown.js library"),
person("John", "Gruber", role = c("ctb", "cph"),
comment = "showdown.js library"),
person("Ivan", "Sagalaev", role = c("ctb", "cph"),
comment = "highlight.js library"),
person(family = "R Core Team", role = c("ctb", "cph"),
comment = "tar implementation from R")
)
Description: Makes it incredibly easy to build interactive web
applications with R. Automatic "reactive" binding between inputs and
outputs and extensive pre-built widgets make it possible to build
beautiful, responsive, and powerful applications with minimal effort.
License: GPL-3
License: GPL-3 | file LICENSE
Depends:
R (>= 2.14.1)
R (>= 3.0.0),
methods
Imports:
stats,
tools,
utils,
methods,
httpuv (>= 1.2.0),
caTools,
RJSONIO,
httpuv (>= 1.3.3),
mime (>= 0.3),
jsonlite (>= 0.9.16),
xtable,
digest
digest,
htmltools (>= 0.3),
R6 (>= 2.0)
Suggests:
datasets,
Cairo (>= 1.5-5),
testthat,
knitr (>= 1.6),
markdown,
Cairo,
testthat
URL: http://www.rstudio.com/shiny/
rmarkdown,
ggplot2
URL: http://shiny.rstudio.com
BugReports: https://github.com/rstudio/shiny/issues
VignetteBuilder: knitr
Collate:
'app.R'
'bootstrap-layout.R'
'conditions.R'
'map.R'
'priorityqueue.R'
'globals.R'
'utils.R'
'bootstrap.R'
'cache.R'
'fileupload.R'
'stack.R'
'graph.R'
'hooks.R'
'html-deps.R'
'htmltools.R'
'image-interact-opts.R'
'image-interact.R'
'imageutils.R'
'input-action.R'
'input-checkbox.R'
'input-checkboxgroup.R'
'input-date.R'
'input-daterange.R'
'input-file.R'
'input-numeric.R'
'input-password.R'
'input-radiobuttons.R'
'input-select.R'
'input-slider.R'
'input-submit.R'
'input-text.R'
'input-utils.R'
'jqueryui.R'
'middleware-shiny.R'
'middleware.R'
'modules.R'
'priorityqueue.R'
'progress.R'
'react.R'
'reactive-domains.R'
'reactives.R'
'render-plot.R'
'render-table.R'
'run-url.R'
'server-input-handlers.R'
'server.R'
'shiny.R'
'shinyui.R'
'shinywrappers.R'
'showcase.R'
'tar.R'
'timer.R'
'tags.R'
'cache.R'
'graph.R'
'react.R'
'reactives.R'
'fileupload.R'
'shiny.R'
'shinywrappers.R'
'shinyui.R'
'slider.R'
'bootstrap.R'
'run-url.R'
'imageutils.R'
'update-input.R'
RoxygenNote: 5.0.1

1515
LICENSE Normal file

File diff suppressed because it is too large Load Diff

108
NAMESPACE
View File

@@ -1,6 +1,10 @@
# Generated by roxygen2: do not edit by hand
S3method("$",reactivevalues)
S3method("$",session_proxy)
S3method("$",shinyoutput)
S3method("$<-",reactivevalues)
S3method("$<-",session_proxy)
S3method("$<-",shinyoutput)
S3method("[",reactivevalues)
S3method("[",shinyoutput)
@@ -11,37 +15,71 @@ S3method("[[",shinyoutput)
S3method("[[<-",reactivevalues)
S3method("[[<-",shinyoutput)
S3method("names<-",reactivevalues)
S3method(as.character,shiny.tag)
S3method(as.character,shiny.tag.list)
S3method(as.list,reactivevalues)
S3method(format,shiny.tag)
S3method(format,shiny.tag.list)
S3method(as.shiny.appobj,character)
S3method(as.shiny.appobj,list)
S3method(as.shiny.appobj,shiny.appobj)
S3method(as.tags,shiny.appobj)
S3method(as.tags,shiny.render.function)
S3method(names,reactivevalues)
S3method(print,reactive)
S3method(print,shiny.tag)
S3method(print,shiny.tag.list)
S3method(print,shiny.appobj)
S3method(str,reactivevalues)
export("conditionStackTrace<-")
export(..stacktraceoff..)
export(..stacktraceon..)
export(HTML)
export(NS)
export(Progress)
export(a)
export(absolutePanel)
export(actionButton)
export(actionLink)
export(addResourcePath)
export(animationOptions)
export(as.shiny.appobj)
export(basicPage)
export(bootstrapLib)
export(bootstrapPage)
export(br)
export(browserViewer)
export(brushOpts)
export(brushedPoints)
export(callModule)
export(captureStackTraces)
export(checkboxGroupInput)
export(checkboxInput)
export(clickOpts)
export(code)
export(column)
export(conditionStackTrace)
export(conditionalPanel)
export(createWebDependency)
export(dataTableOutput)
export(dateInput)
export(dateRangeInput)
export(dblclickOpts)
export(dialogViewer)
export(div)
export(downloadButton)
export(downloadHandler)
export(downloadLink)
export(em)
export(eventReactive)
export(exprToFunction)
export(extractStackTrace)
export(fileInput)
export(fillCol)
export(fillPage)
export(fillRow)
export(fixedPage)
export(fixedPanel)
export(fixedRow)
export(flowLayout)
export(fluidPage)
export(fluidRow)
export(formatStackTrace)
export(getDefaultReactiveDomain)
export(h1)
export(h2)
export(h3)
@@ -50,29 +88,58 @@ export(h5)
export(h6)
export(headerPanel)
export(helpText)
export(hoverOpts)
export(hr)
export(htmlOutput)
export(htmlTemplate)
export(icon)
export(imageOutput)
export(img)
export(incProgress)
export(includeCSS)
export(includeHTML)
export(includeMarkdown)
export(includeScript)
export(includeText)
export(inputPanel)
export(installExprFunction)
export(invalidateLater)
export(is.reactive)
export(is.reactivevalues)
export(is.shiny.appobj)
export(is.singleton)
export(isolate)
export(knit_print.html)
export(knit_print.reactive)
export(knit_print.shiny.appobj)
export(knit_print.shiny.render.function)
export(knit_print.shiny.tag)
export(knit_print.shiny.tag.list)
export(mainPanel)
export(makeReactiveBinding)
export(markRenderFunction)
export(maskReactiveContext)
export(navbarMenu)
export(navbarPage)
export(navlistPanel)
export(nearPoints)
export(need)
export(ns.sep)
export(numericInput)
export(observe)
export(observeEvent)
export(onReactiveDomainEnded)
export(outputOptions)
export(p)
export(pageWithSidebar)
export(paneViewer)
export(parseQueryString)
export(passwordInput)
export(plotOutput)
export(plotPNG)
export(pre)
export(printError)
export(printStackTrace)
export(radioButtons)
export(reactive)
export(reactiveFileReader)
@@ -85,6 +152,8 @@ export(reactiveTimer)
export(reactiveUI)
export(reactiveValues)
export(reactiveValuesToList)
export(registerInputHandler)
export(removeInputHandler)
export(renderDataTable)
export(renderImage)
export(renderPlot)
@@ -93,26 +162,38 @@ export(renderTable)
export(renderText)
export(renderUI)
export(repeatable)
export(req)
export(runApp)
export(runExample)
export(runGadget)
export(runGist)
export(runGitHub)
export(runUrl)
export(selectInput)
export(selectizeInput)
export(serverInfo)
export(setProgress)
export(shinyApp)
export(shinyAppDir)
export(shinyAppFile)
export(shinyServer)
export(shinyUI)
export(showReactLog)
export(sidebarLayout)
export(sidebarPanel)
export(singleton)
export(sliderInput)
export(span)
export(splitLayout)
export(stopApp)
export(strong)
export(submitButton)
export(suppressDependencies)
export(tabPanel)
export(tableOutput)
export(tabsetPanel)
export(tag)
export(tagAppendAttributes)
export(tagAppendChild)
export(tagAppendChildren)
export(tagList)
@@ -120,24 +201,35 @@ export(tagSetChildren)
export(tags)
export(textInput)
export(textOutput)
export(titlePanel)
export(uiOutput)
export(updateCheckboxGroupInput)
export(updateCheckboxInput)
export(updateDateInput)
export(updateDateRangeInput)
export(updateNavbarPage)
export(updateNavlistPanel)
export(updateNumericInput)
export(updateRadioButtons)
export(updateSelectInput)
export(updateSelectizeInput)
export(updateSliderInput)
export(updateTabsetPanel)
export(updateTextInput)
export(validate)
export(validateCssUnit)
export(verbatimTextOutput)
export(verticalLayout)
export(wellPanel)
export(withLogErrors)
export(withMathJax)
export(withProgress)
export(withReactiveDomain)
export(withTags)
import(RJSONIO)
import(caTools)
import(R6)
import(digest)
import(htmltools)
import(httpuv)
import(methods)
import(mime)
import(xtable)

571
NEWS
View File

@@ -1,3 +1,570 @@
shiny 0.13.0
--------------------------------------------------------------------------------
* Fixed #962: plot interactions did not work with the development version of
ggplot2 (after ggplot2 1.0.1).
* Fixed #902: the `drag_drop` plugin of the selectize input did not work.
* Fixed #933: `updateSliderInput()` does not work when only the label is
updated.
* Multiple imageOutput/plotOutput calls can now share the same brush id. Shiny
will ensure that performing a brush operation will clear any other brush with
the same id.
* Added `placeholder` option to `textInput`.
* Improved support for Unicode characters on Windows (#968).
* Fixed bug in `selectInput` and `selectizeInput` where values with double
quotes were not properly escaped.
* `runApp()` can now take a path to any .R file that yields a `shinyApp` object;
previously, the path had to be a directory that contained an app.R file (or
server.R if using separately defined server and UI). Similarly, introduced
`shinyAppFile()` function which creates a `shinyApp` object for an .R file
path, just as `shinyAppDir()` does for a directory path.
* Introduced Shiny Modules, which are designed to 1) simplify the reuse of
Shiny UI/server logic and 2) make authoring and maintaining complex Shiny
apps much easier. See the article linked from `?callModule`.
* `invalidateLater` and `reactiveTimer` no longer require an explicit `session`
argument; the default value uses the current session.
* Added `session$reload()` method, the equivalent of hitting the browser's
Reload button.
* Added `shiny.autoreload` option, which will automatically cause browsers to
reload whenever Shiny app files change on disk. This is intended to shorten
the feedback cycle when tweaking UI code.
* Errors are now printed with stack traces! This should make it tremendously
easier to track down the causes of errors in Shiny. Try it by calling
`stop("message")` from within an output, reactive, or observer. Shiny itself
adds a lot of noise to the call stack, so by default, it attempts to hide all
but the relevant levels of the call stack. You can turn off this behavior by
setting `options(shiny.fullstacktrace=TRUE)` before or during app startup.
* Fixed #1018: the selected value of a selectize input is guaranteed to be
selected in server-side mode.
* Added `req` function, which provides a simple way to prevent a reactive,
observer, or output from executing until all required inputs and values are
available. (Similar functionality has been available for a while using
validate/need, but req provides a much simpler and more direct interface.)
* Improve stability with Shiny Server when many subapps are used, by deferring
the loading of subapp iframes until a connection has first been established
with the server.
* Upgrade to Font Awesome 4.5.0.
* Upgraded to Bootstrap 3.3.5.
* Switched to an almost-complete build of jQuery UI with the exception of the
datepicker extension, which conflicts with Shiny's date picker.
* Added `fillPage` function, an alternative to `fluidPage`, `fixedPage`, etc.
that is designed for apps that fill the entire available page width/height.
* Added `fillRow` and `fillCol` functions, for laying out proportional grids in
`fillPage`. For modern browsers only.
* Added `runGadget`, `paneViewer`, `dialogViewer`, and `browserViewer`
functions to support Shiny Gadgets. More detailed docs about gadgets coming
soon.
* Added support for the new htmltools 0.3 feature `htmlTemplate`. It's now
possible to use regular HTML markup to design your UI, but still use R
expressions to define inputs, outputs, and HTML widgets.
shiny 0.12.2
--------------------------------------------------------------------------------
* GitHub changed URLs for gists from .tar.gz to .zip, so `runGist` was updated
to work with the new URLs.
* Callbacks from the session object are now guaranteed to execute in the order
in which registration occurred.
* Minor bugs in sliderInput's animation behavior have been fixed. (#852)
* Updated to ion.rangeSlider to 2.0.12.
* Added `shiny.minified` option, which controls whether the minified version
of shiny.js is used. Setting it to FALSe can be useful for debugging. (#826,
#850)
* Fixed an issue for outputting plots from ggplot objects which also have an
additional class whose print method takes precedence over `print.ggplot`.
(#840, 841)
* Added `width` option to Shiny's input functions. (#589, #834)
* Added two alias functions of `updateTabsetPanel()` to update the selected tab:
`updateNavbarPage()` and `updateNavlistPanel()`. (#881)
* All non-base functions are now explicitly namespaced, to pass checks in
R-devel.
* Shiny now correctly handles HTTP HEAD requests. (#876)
shiny 0.12.1
--------------------------------------------------------------------------------
* Fixed an issue where unbindAll() causes subsequent bindAll() to be ignored for
previously bound outputs. (#856)
* Undeprecate `dataTableOutput` and `renderDataTable`, which had been deprecated
in favor of the new DT package. The DT package is a bit too new and has a
slightly different API, we were too hasty in deprecating the existing Shiny
functions.
shiny 0.12.0
--------------------------------------------------------------------------------
* Switched from RJSONIO to jsonlite. This improves consistency and speed when
converting between R data structures and JSON. One notable change is that
POSIXt objects are now serialized to JSON in UTC8601 format (like
"2015-03-20T20:00:00Z"), instead of as seconds from the epoch).
* In addition to the existing support for clicking and hovering on plots
created by base graphics, added support for double-clicking and brushing.
(#769)
* Added support for clicking, hovering, double-clicking, and brushing for
plots created by ggplot2, including support for facets. (#802)
* Added `nearPoints` and `brushedPoints` functions for easily selecting rows of
data that are clicked/hovered, or brushed. (#802)
* Added `shiny.port` option. If this is option is set, `runApp()` will listen on
this port by default. (#756)
* `runUrl`, `runGist`, and `runGitHub` now can save downloaded applications,
with the `destdir` argument. (#688)
* Restored ability to set labels for `selectInput`. (#741)
* Travis continuous integration now uses Travis's native R support.
* Fixed encoding issue when the server receives data from the client browser.
(#742)
* The `session` object now has class `ShinySession`, making it easier to test
whether an object is indeed a session object. (#720, #746)
* Fix JavaScript error when an output appears in nested uiOutputs. (Thanks,
Gregory Zhang. #749)
* Eliminate delay on receiving new value when `updateSliderInput(value=...)` is
called.
* Updated to DataTables (Javascript library) 1.10.5.
* Fixed downloading of files that have no filename extension. (#575, #753)
* Fixed bug where nested UI outputs broke outputs. (#749, #750)
* Removed unneeded HTML ID attributes for `checkboxGroupInputs` and
`radioButtons`. (#684)
* Fixed bug where checkboxes were still active even after `Shiny.unbindAll()`
was called. (#206)
* The server side selectize input will load the first 1000 options by default
before users start to type and search in the box. (#823)
* renderDataTable() and dataTableOutput() have been deprecated in shiny and will
be removed in future versions of shiny. Please use the DT package instead:
http://rstudio.github.io/DT/ (#807)
shiny 0.11.1
--------------------------------------------------------------------------------
* Major client-side performance improvements for pages that have many
conditionalPanels, tabPanels, and plotOutputs. (#693, #717, #723)
* `tabPanel`s now use the `title` for `value` by default. This fixes a bug
in which an icon in the title caused problems with a conditionalPanel's test
condition. (#725, #728)
* `selectInput` now has a `size` argument to control the height of the input
box. (#729)
* `navbarPage` no longer includes a first row of extra whitespace when
`header=NULL`. (#722)
* `selectInput`s now use Bootstrap styling when `selectize=FALSE`. (#724)
* Better vertical spacing of label for checkbox groups and radio buttons.
* `selectInput` correctly uses width for both selectize and non-selectize
inputs. (#702)
* The wrapper tag generated by `htmlOutput` and `uiOutput` can now be any type
of HTML tag, instead of just span and div. Also, custom classes are now
allowed on the tag. (#704)
* Slider problems in IE 11 and Chrome on touchscreen-equipped Windows computers
have been fixed. (#700)
* Sliders now work correctly with draggable panels. (#711)
* Fixed arguments in `fixedPanel`. (#709)
* downloadHandler content callback functions are now invoked with a temp file
name that has the same extension as the final filename that will be used by
the download. This is to deal with the fact that some file writing functions
in R will auto-append the extension for their file type (pdf, zip).
shiny 0.11
--------------------------------------------------------------------------------
* Changed sliders from jquery-slider to ion.rangeSlider. These sliders have
an improved appearance, support updating more properties from the server,
and can be controlled with keyboard input.
* Switched from Bootstrap 2 to Bootstrap 3. For most users, this will work
seamlessly, but some users may need to use the shinybootstrap2 package for
backward compatibility.
* The UI of a Shiny app can now have a body tag. This is useful for CSS
templates that use classes on the body tag.
* `actionButton` and `actionLink` now pass their `...` arguments to the
underlying tag function. (#607)
* Added `observeEvent` and `eventReactive` functions for clearer, more concise
handling of `actionButton`, plot clicks, and other naturally-imperative
inputs.
* Errors that happen in reactives no longer prevent any remaining pending
observers from executing. It is also now possible for users to control how
errors are handled, with the 'shiny.observer.error' global option. (#603,
#604)
* Added an `escape` argument to `renderDataTable()` to escape the HTML entities
in the data table for security reasons. This might break tables from previous
versions of shiny that use raw HTML in the table content, and the old behavior
can be brought back by `escape = FALSE` if you are aware of the security
implications. (#627)
* Changed the URI encoding/decoding functions internally to use `encodeURI()`,
`encodeURIComponent()`, and `decodeURIComponent()` from the httpuv package
instead of `utils::URLencode()` and `utils::URLdecode()`. (#630)
* Shiny's web assets are now minified.
* The default reactive domain is now available in event handler functions. (#669)
* Password input fields can now be used, with `passwordInput()`. (#672)
shiny 0.10.2.2
--------------------------------------------------------------------------------
* Remove use of `rstudio::viewer` in a code example, for R CMD check.
shiny 0.10.2.1
--------------------------------------------------------------------------------
* Changed some examples to use \donttest instead of \dontrun.
shiny 0.10.2
--------------------------------------------------------------------------------
* The minimal version of R required for the shiny package is 3.0.0 now.
* Shiny apps can now consist of a single file, app.R, instead of ui.R and
server.R.
* Upgraded DataTables from 1.9.4 to 1.10.2. This might be a breaking change if
you have customized the DataTables options in your apps. (More info:
https://github.com/rstudio/shiny/pull/558)
* File uploading via `fileInput()` works for Internet Explorer 8 and 9 now. Note
IE8/9 do not support multiple files from a single file input. If you need to
upload multiple files, you have to use one file input for each file.
* Switched away from reference classes to R6.
* Reactive log performance has been greatly improved.
* Added `Progress` and `withProgress`, to display the progress of computation
on the client browser.
* Fixed #557: updateSelectizeInput(choices, server = TRUE) did not work when
`choices` is a character vector.
* Searching in DataTables is case-insensitive and the search strings are not
treated as regular expressions by default now. If you want case-sensitive
searching or regular expressions, you can use the configuration options
`search$caseInsensitive` and `search$regex`, e.g. `renderDataTable(...,
options = list(search = list(caseInsensitve = FALSE, regex = TRUE)))`.
* Added support for `htmltools::htmlDependency`'s new `attachment` parameter to
`renderUI`/`uiOutput`.
* Exported `createWebDependency`. It takes an `htmltools::htmlDependency` object
and makes it available over Shiny's built-in web server.
* Custom output bindings can now render `htmltools::htmlDependency` objects at
runtime using `Shiny.renderDependencies()`.
* Fixes to rounding behavior of sliderInput. (#301, #502)
* Updated selectize.js to version 0.11.2. (#596)
* Added `position` parameter to `navbarPage`.
shiny 0.10.1
--------------------------------------------------------------------------------
* Added Unicode support for Windows. Shiny apps running on Windows must use the
UTF-8 encoding for ui.R and server.R (also the optional global.R) if they
contain non-ASCII characters. See this article for details and examples:
http://shiny.rstudio.com/gallery/unicode-characters.html (#516)
* `runGitHub()` also allows the 'username/repo' syntax now, which is equivalent
to `runGitHub('repo', 'username')`. (#427)
* `navbarPage()` now accepts a `windowTitle` parameter to set the web browser
page title to something other than the title displayed in the navbar.
* Added an `inline` argument to `textOutput()`, `imageOutput()`, `plotOutput()`,
and `htmlOutput()`. When `inline = TRUE`, these outputs will be put in
`span()` instead of the default `div()`. This occurs automatically when these
outputs are created via the inline expressions (e.g. `r renderText(expr)`) in
R Markdown documents. See an R Markdown example at
http://shiny.rstudio.com/gallery/inline-output.html (#512)
* Added support for option groups in the select/selectize inputs. When the
`choices` argument for `selectInput()`/`selectizeInput()` is a list of
sub-lists and any sub-list is of length greater than 1, the HTML tag
`<optgroup>` will be used. See an example at
http://shiny.rstudio.com/gallery/option-groups-for-selectize-input.html (#542)
shiny 0.10.0
--------------------------------------------------------------------------------
* BREAKING CHANGE: By default, observers now terminate themselves if they were
created during a session and that session ends. See ?domains for more details.
* Shiny can now be used in R Markdown v2 documents, to create "Shiny Docs":
reports and presentations that combine narrative, statically computed output,
and fully dynamic inputs and outputs. For more info, including examples, see
http://rmarkdown.rstudio.com/authoring_shiny.html.
* The `session` object that can be passed into a server function (e.g.
shinyServer(function(input, output, session) {...})) is now documented: see
`?session`.
* Most inputs can now accept `NULL` label values to omit the label altogether.
* New `actionLink` input control; like `actionButton`, but with the appearance
of a normal link.
* `renderPlot` now calls `print` on its result if it's visible (i.e. no more
explicit `print()` required for ggplot2).
* Introduced Shiny app objects (see `?shinyApp`). These essentially replace the
little-advertised ability for `runApp` to take a `list(ui=..., server=...)`
as the first argument instead of a directory (though that ability remains for
backward compatibility). Unlike those lists, Shiny app objects are tagged with
class `shiny.appobj` so they can be run simply by printing them.
* Added `maskReactiveContext` function. It blocks the current reactive context,
to evaluate expressions that shouldn't use reactive sources directly. (This
should not be commonly needed.)
* Added `flowLayout`, `splitLayout`, and `inputPanel` functions for putting UI
elements side by side. `flowLayout` lays out its children in a left-to-right,
top-to-bottom arrangement. `splitLayout` evenly divides its horizontal space
among its children (or unevenly divides if `cellWidths` argument is provided).
`inputPanel` is like `flowPanel`, but with a light grey background, and is
intended to be used to encapsulate small input controls wherever vertical
space is at a premium.
* Added `serverInfo` to obtain info about the Shiny Server if the app is served
through it.
* Added an `inline` argument (TRUE/FALSE) in `checkboxGroupInput()` and
`radioButtons()` to allow the horizontal layout (inline = TRUE) of checkboxes
or radio buttons. (Thanks, @saurfang, #481)
* `sliderInput` and `selectizeInput`/`selectInput` now use a standard horizontal
size instead of filling up all available horizontal space. Pass `width="100%"`
explicitly for the old behavior.
* Added the `updateSelectizeInput()` function to make it possible to process
searching on the server side (i.e. using R), which can be much faster than the
client side processing (i.e. using HTML and JavaScript). See the article at
http://shiny.rstudio.com/articles/selectize.html for a detailed introduction.
* Fixed a bug of renderDataTable() when the data object only has 1 row and 1
column. (Thanks, ZJ Dai, #429)
* `renderPrint` gained a new argument 'width' to control the width of the text
output, e.g. renderPrint({mtcars}, width = 40).
* Fixed #220: the zip file for a directory created by some programs may not have
the directory name as its first entry, in which case runUrl() can fail. (#220)
* `runGitHub()` can also take a value of the form "username/repo" in its first
argument, e.g. both runGitHub("shiny_example", "rstudio") and
runGitHub("rstudio/shiny_example") are valid ways to run the GitHub repo.
shiny 0.9.1
--------------------------------------------------------------------------------
* Fixed warning 'Error in Context$new : could not find function "loadMethod"'
that was happening to dependent packages on "R CMD check".
shiny 0.9.0
--------------------------------------------------------------------------------
* BREAKING CHANGE: Added a `host` parameter to runApp() and runExample(),
which defaults to the shiny.host option if it is non-NULL, or "127.0.0.1"
otherwise. This means that by default, Shiny applications can only be
accessed on the same machine from which they are served. To allow other
clients to connect, as in previous versions of Shiny, use "0.0.0.0"
(or the IP address of one of your network interfaces, if you care to be
explicit about it).
* Added a new function `selectizeInput()` to use the JavaScript library
selectize.js (https://github.com/brianreavis/selectize.js), which extends
the basic select input in many aspects.
* The `selectInput()` function also gained a new argument `selectize = TRUE`
to makes use of selectize.js by default. If you want to revert back to the
original select input, you have to call selectInput(..., selectize = FALSE).
* Added Showcase mode, which displays the R code for an app right in the app
itself. You can invoke Showcase mode by passing `display.mode="showcase"`
to the `runApp()` function. Or, if an app is designed to run in Showcase
mode by default, add a DESCRIPTION file in the app dir with Title, Author,
and License fields; with "Type: Shiny"; and with "DisplayMode: Showcase".
* Upgraded to Bootstrap 2.3.2 and jQuery 1.11.0.
* Make `tags$head()` and `singleton()` behave correctly when used with
`renderUI()` and `uiOutput()`. Previously, "hoisting content to the head"
and "only rendering items a single time" were features that worked only
when the page was initially loading, not in dynamic rendering.
* Files are now sourced with the `keep.source` option, to help with debugging
and profiling.
* Support user-defined input parsers for data coming in from JavaScript using
the parseShinyInput method.
* Fixed the bug #299: renderDataTable() can deal with 0-row data frames now.
(reported by Harlan Harris)
* Added `navbarPage()` and `navbarMenu()` functions to create applications
with multiple top level panels.
* Added `navlistPanel()` function to create layouts with a a bootstrap
navlist on the left and tabPanels on the right
* Added `type` parameter to `tabsetPanel()` to enable the use of pill
style tabs in addition to the standard ones.
* Added `position` paramter to `tabsetPanel()` to enable positioning of tabs
above, below, left, or right of tab content.
* Added `fluidPage()` and `fixedPage()` functions as well as related row and
column layout functions for creating arbitrary bootstrap grid layouts.
* Added `hr()` builder function for creating horizontal rules.
* Automatically concatenate duplicate attributes in tag definitions
* Added `responsive` parameter to page building functions for opting-out of
bootstrap responsive css.
* Added `theme` parameter to page building functions for specifying alternate
bootstrap css styles.
* Added `icon()` function for embedding icons from the
[font awesome](http://fontawesome.io/) icon library
* Added `makeReactiveBinding` function to turn a "regular" variable into a
reactive one (i.e. reading the variable makes the current reactive context
dependent on it, and setting the variable is a source of reactivity).
* Added a function `withMathJax()` to include the MathJax library in an app.
* The argument `selected` in checkboxGroupInput(), selectInput(), and
radioButtons() refers to the value(s) instead of the name(s) of the
argument `choices` now. For example, the value of the `selected` argument
in selectInput(..., choices = c('Label 1' = 'x1', 'Label 2' = 'x2'),
selected = 'Label 2') must be updated to 'x2', although names/labels will
be automatically converted to values internally for backward
compatibility. The same change applies to updateCheckboxGroupInput(),
updateSelectInput(), and updateRadioButtons() as well. (#340)
* Now it is possible to only update the value of a checkbox group, select input,
or radio buttons using the `selected` argument without providing the
`choices` argument in updateCheckboxGroupInput(), updateSelectInput(), and
updateRadioButtons(), respectively. (#340)
* Added `absolutePanel` and `fixedPanel` functions for creating absolute-
and fixed-position panels. They can be easily made user-draggable by
specifying `draggable = TRUE`.
* For the `options` argument of the function `renderDataTable()`, we can
pass literal JavaScript code to the DataTables library via `I()`. This
makes it possible to use any JavaScript object in the options, e.g. a
JavaScript function (which is not supported in JSON). See
`?renderDataTable` for details and examples.
* DataTables also works under IE8 now.
* Fixed a bug in DataTables pagination when searching is turned on, which
caused failures for matrices as well as empty rows when displaying data
frames using renderDataTable().
* The `options` argument in `renderDataTable()` can also take a function
that returns a list. This makes it possible to use reactive values in the
options. (#392)
* `renderDataTable()` respects more DataTables options now: (1) either
bPaginate = FALSE or iDisplayLength = -1 will disable pagination (i.e. all
rows are returned from the data); besides, this means we can also use -1
in the length menu, e.g. aLengthMenu = list(c(10, 30, -1), list(10, 30,
'All')); (2) we can disable searching for individual columns through the
bSearchable option, e.g. aoColumns = list(list(bSearchable = FALSE),
list(bSearchable = TRUE),...) (the search box for the first column is
hidden); (3) we can turn off searching entirely (for both global searching
and individual columns) using the option bFilter = FALSE.
* Added an argument `callback` in `renderDataTable()` so that a custom
JavaScript function can be applied to the DataTable object. This makes it
much easier to use DataTables plug-ins.
* For numeric columns in a DataTable, the search boxes support lower and
upper bounds now: a search query of the form "lower,upper" (without
quotes) indicates the limits [lower, upper]. For a column X, this means
the rows corresponding to X >= lower & X <= upper are returned. If we omit
either the lower limit or the upper limit, only the other limit will be
used, e.g. ",upper" means X <= upper.
* `updateNumericInput(value)` tries to preserve numeric precision by avoiding
scientific notation when possible, e.g. 102145 is no longer rounded to
1.0214e+05 = 102140. (Thanks, Martin Loos. #401)
* `sliderInput()` no longer treats a label wrapped in HTML() as plain text,
e.g. the label in sliderInput(..., label = HTML('<em>A Label</em>')) will
not be escaped any more. (#119)
* Fixed #306: the trailing slash in a path could fail `addResourcePath()`
under Windows. (Thanks, ZJ Dai)
* Dots are now legal characters for inputId/outputId. (Thanks, Kevin
Lindquist. #358)
shiny 0.8.0
--------------------------------------------------------------------------------
@@ -14,7 +581,7 @@ shiny 0.8.0
searching (global search or search by individual columns), sorting (by
single or multiple columns). All these features are implemented on the R
side; for example, we can use R regular expressions for searching.
Besides, it also uses the Twitter Bootstrap CSS style. See the full
Besides, it also uses the Bootstrap CSS style. See the full
documentation and examples in the tutorial:
http://rstudio.github.io/shiny/tutorial/#datatables
@@ -313,7 +880,7 @@ shiny 0.1.8
* Fix issue #27: Warnings cause reactive functions to stop executing.
* The server.R and ui.R filenames are now case insensitive.
* Add `wellPanel` function for creating inset areas on the page.
* Add `bootstrapPage` function for creating new Twitter Bootstrap based
* Add `bootstrapPage` function for creating new Bootstrap based
layouts from scratch.

468
R/app.R Normal file
View File

@@ -0,0 +1,468 @@
# TODO: Subapp global.R
#' Create a Shiny app object
#'
#' These functions create Shiny app objects from either an explicit UI/server
#' pair (\code{shinyApp}), or by passing the path of a directory that contains a
#' Shiny app (\code{shinyAppDir}). You generally shouldn't need to use these
#' functions to create/run applications; they are intended for interoperability
#' purposes, such as embedding Shiny apps inside a \pkg{knitr} document.
#'
#' Normally when this function is used at the R console, the Shiny app object is
#' automatically passed to the \code{print()} function, which runs the app. If
#' this is called in the middle of a function, the value will not be passed to
#' \code{print()} and the app will not be run. To make the app run, pass the app
#' object to \code{print()} or \code{\link{runApp}()}.
#'
#' @param ui The UI definition of the app (for example, a call to
#' \code{fluidPage()} with nested controls)
#' @param server A server function
#' @param onStart A function that will be called before the app is actually run.
#' This is only needed for \code{shinyAppObj}, since in the \code{shinyAppDir}
#' case, a \code{global.R} file can be used for this purpose.
#' @param options Named options that should be passed to the `runApp` call. You
#' can also specify \code{width} and \code{height} parameters which provide a
#' hint to the embedding environment about the ideal height/width for the app.
#' @param uiPattern A regular expression that will be applied to each \code{GET}
#' request to determine whether the \code{ui} should be used to handle the
#' request. Note that the entire request path must match the regular
#' expression in order for the match to be considered successful.
#' @return An object that represents the app. Printing the object or passing it
#' to \code{\link{runApp}} will run the app.
#'
#' @examples
#' ## Only run this example in interactive R sessions
#' if (interactive()) {
#' shinyApp(
#' ui = fluidPage(
#' numericInput("n", "n", 1),
#' plotOutput("plot")
#' ),
#' server = function(input, output) {
#' output$plot <- renderPlot( plot(head(cars, input$n)) )
#' }
#' )
#'
#' shinyAppDir(system.file("examples/01_hello", package="shiny"))
#'
#'
#' # The object can be passed to runApp()
#' app <- shinyApp(
#' ui = fluidPage(
#' numericInput("n", "n", 1),
#' plotOutput("plot")
#' ),
#' server = function(input, output) {
#' output$plot <- renderPlot( plot(head(cars, input$n)) )
#' }
#' )
#'
#' runApp(app)
#' }
#'
#' @export
shinyApp <- function(ui=NULL, server=NULL, onStart=NULL, options=list(),
uiPattern="/") {
if (is.null(server)) {
stop("`server` missing from shinyApp")
}
# Ensure that the entire path is a match
uiPattern <- sprintf("^%s$", uiPattern)
httpHandler <- uiHttpHandler(ui, uiPattern)
serverFuncSource <- function() {
server
}
structure(
list(
httpHandler = httpHandler,
serverFuncSource = serverFuncSource,
onStart = onStart,
options = options),
class = "shiny.appobj"
)
}
#' @rdname shinyApp
#' @param appDir Path to directory that contains a Shiny app (i.e. a server.R
#' file and either ui.R or www/index.html)
#' @export
shinyAppDir <- function(appDir, options=list()) {
if (!utils::file_test('-d', appDir)) {
stop("No Shiny application exists at the path \"", appDir, "\"")
}
# In case it's a relative path, convert to absolute (so we're not adversely
# affected by future changes to the path)
appDir <- normalizePath(appDir, mustWork = TRUE)
if (file.exists.ci(appDir, "server.R")) {
shinyAppDir_serverR(appDir, options = options)
} else if (file.exists.ci(appDir, "app.R")) {
shinyAppDir_appR("app.R", appDir, options = options)
} else {
stop("App dir must contain either app.R or server.R.")
}
}
#' @rdname shinyApp
#' @param appFile Path to a .R file containing a Shiny application
#' @export
shinyAppFile <- function(appFile, options=list()) {
appFile <- normalizePath(appFile, mustWork = TRUE)
shinyAppDir_appR(basename(appFile), dirname(appFile), options = options)
}
# This reads in an app dir in the case that there's a server.R (and ui.R/www)
# present, and returns a shiny.appobj.
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.
# uiHandlerSource is a function that returns an HTTP handler for serving up
# ui.R as a webpage. The "cachedFuncWithFile" call makes sure that the closure
# we're creating here only gets executed when ui.R's contents change.
uiHandlerSource <- cachedFuncWithFile(appDir, "ui.R", case.sensitive = FALSE,
function(uiR) {
if (file.exists(uiR)) {
# If ui.R contains a call to shinyUI (which sets .globals$ui), use that.
# If not, then take the last expression that's returned from ui.R.
.globals$ui <- NULL
on.exit(.globals$ui <- NULL, add = FALSE)
ui <- sourceUTF8(uiR, envir = new.env(parent = globalenv()))
if (!is.null(.globals$ui)) {
ui <- .globals$ui[[1]]
}
return(uiHttpHandler(ui))
} else {
return(function(req) NULL)
}
}
)
uiHandler <- function(req) {
uiHandlerSource()(req)
}
wwwDir <- file.path.ci(appDir, "www")
fallbackWWWDir <- system.file("www-dir", package = "shiny")
serverSource <- cachedFuncWithFile(appDir, "server.R", case.sensitive = FALSE,
function(serverR) {
# If server.R contains a call to shinyServer (which sets .globals$server),
# use that. If not, then take the last expression that's returned from
# server.R.
.globals$server <- NULL
on.exit(.globals$server <- NULL, add = TRUE)
result <- sourceUTF8(serverR, envir = new.env(parent = globalenv()))
if (!is.null(.globals$server)) {
result <- .globals$server[[1]]
}
return(result)
}
)
# This function stands in for the server function, and reloads the
# real server function as necessary whenever server.R changes
serverFuncSource <- function() {
serverFunction <- serverSource()
if (is.null(serverFunction)) {
return(function(input, output) NULL)
} else if (is.function(serverFunction)) {
# This is what we normally expect; run the server function
return(serverFunction)
} else {
stop("server.R returned an object of unexpected type: ",
typeof(serverFunction))
}
}
oldwd <- NULL
monitorHandle <- NULL
onStart <- function() {
oldwd <<- getwd()
setwd(appDir)
monitorHandle <<- initAutoReloadMonitor(appDir)
if (file.exists(file.path.ci(appDir, "global.R")))
sourceUTF8(file.path.ci(appDir, "global.R"))
}
onEnd <- function() {
setwd(oldwd)
monitorHandle()
monitorHandle <<- NULL
}
structure(
list(
httpHandler = joinHandlers(c(uiHandler, wwwDir, fallbackWWWDir)),
serverFuncSource = serverFuncSource,
onStart = onStart,
onEnd = onEnd,
options = options),
class = "shiny.appobj"
)
}
# Start a reactive observer that continually monitors dir for changes to files
# that have the extensions: r, htm, html, js, css, png, jpg, jpeg, gif. Case is
# ignored when checking extensions. If any changes are detected, all connected
# Shiny sessions are reloaded.
#
# Use option(shiny.autoreload = TRUE) to enable this behavior. Since monitoring
# for changes is expensive (we are polling for mtimes here, nothing fancy) 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:
# option(shiny.autoreload.pattern = glob2rx("ui.R"))
#
# The return value is a function that halts monitoring when called.
initAutoReloadMonitor <- function(dir) {
if (!getOption("shiny.autoreload", FALSE)) {
return(function(){})
}
filePattern <- getOption("shiny.autoreload.pattern",
".*\\.(r|html?|js|css|png|jpe?g|gif)$")
lastValue <- NULL
obs <- observe({
files <- sort(list.files(dir, pattern = filePattern, recursive = TRUE,
ignore.case = TRUE))
times <- file.info(files)$mtime
names(times) <- files
if (is.null(lastValue)) {
# First run
lastValue <<- times
} else if (!identical(lastValue, times)) {
# We've changed!
lastValue <<- times
for (session in appsByToken$values()) {
session$reload()
}
}
invalidateLater(getOption("shiny.autoreload.interval", 500))
})
obs$destroy
}
# This reads in an app dir for a single-file application (e.g. app.R), and
# returns a shiny.appobj.
shinyAppDir_appR <- function(fileName, appDir, options=list()) {
fullpath <- file.path.ci(appDir, fileName)
# This sources app.R and caches the content. When appObj() is called but
# app.R hasn't changed, it won't re-source the file. But if called and
# app.R has changed, it'll re-source the file and return the result.
appObj <- cachedFuncWithFile(appDir, fileName, case.sensitive = FALSE,
function(appR) {
result <- sourceUTF8(fullpath, envir = new.env(parent = globalenv()))
if (!is.shiny.appobj(result))
stop("app.R did not return a shiny.appobj object.")
return(result)
}
)
# A function that invokes the http handler from the appObj in app.R, but
# since this uses appObj(), it only re-sources the file when it changes.
dynHttpHandler <- function(...) {
appObj()$httpHandler(...)
}
dynServerFuncSource <- function(...) {
appObj()$serverFuncSource(...)
}
wwwDir <- file.path.ci(appDir, "www")
fallbackWWWDir <- system.file("www-dir", package = "shiny")
oldwd <- NULL
monitorHandle <- NULL
onStart <- function() {
oldwd <<- getwd()
setwd(appDir)
monitorHandle <<- initAutoReloadMonitor(appDir)
}
onEnd <- function() {
setwd(oldwd)
monitorHandle()
monitorHandle <<- NULL
}
structure(
list(
httpHandler = joinHandlers(c(dynHttpHandler, wwwDir, fallbackWWWDir)),
serverFuncSource = dynServerFuncSource,
onStart = onStart,
onEnd = onEnd,
options = options
),
class = "shiny.appobj"
)
}
#' @rdname shinyApp
#' @param x Object to convert to a Shiny app.
#' @export
as.shiny.appobj <- function(x) {
UseMethod("as.shiny.appobj", x)
}
#' @rdname shinyApp
#' @export
as.shiny.appobj.shiny.appobj <- function(x) {
x
}
#' @rdname shinyApp
#' @export
as.shiny.appobj.list <- function(x) {
shinyApp(ui = x$ui, server = x$server)
}
#' @rdname shinyApp
#' @export
as.shiny.appobj.character <- function(x) {
if (identical(tolower(tools::file_ext(x)), "r"))
shinyAppFile(x)
else
shinyAppDir(x)
}
#' @rdname shinyApp
#' @export
is.shiny.appobj <- function(x) {
inherits(x, "shiny.appobj")
}
#' @rdname shinyApp
#' @param ... Additional parameters to be passed to print.
#' @export
print.shiny.appobj <- function(x, ...) {
opts <- x$options %OR% list()
opts <- opts[names(opts) %in%
c("port", "launch.browser", "host", "quiet", "display.mode")]
args <- c(list(x), opts)
do.call(runApp, args)
}
#' @rdname shinyApp
#' @method as.tags shiny.appobj
#' @export
as.tags.shiny.appobj <- function(x, ...) {
# jcheng 06/06/2014: Unfortunate copy/paste between this function and
# knit_print.shiny.appobj, but I am trying to make the most conservative
# change possible due to upcoming release.
opts <- x$options %OR% list()
width <- if (is.null(opts$width)) "100%" else opts$width
height <- if (is.null(opts$height)) "400" else opts$height
path <- addSubApp(x)
deferredIFrame(path, width, height)
}
# Generate subapp iframes in such a way that they will not actually load right
# away. Loading subapps immediately upon app load can result in a storm of
# connections, all of which are contending for the few concurrent connections
# that a browser will make to a specific origin. Instead, we load dummy iframes
# and let the client load them when convenient. (See the initIframes function in
# init_shiny.js.)
deferredIFrame <- function(path, width, height) {
tags$iframe("data-deferred-src" = path,
width = width, height = height,
class = "shiny-frame shiny-frame-deferred"
)
}
#' Knitr S3 methods
#'
#' These S3 methods are necessary to help Shiny applications and UI chunks embed
#' themselves in knitr/rmarkdown documents.
#'
#' @name knitr_methods
#' @param x Object to knit_print
#' @param ... Additional knit_print arguments
NULL
# If there's an R Markdown runtime option set but it isn't set to Shiny, then
# return a warning indicating the runtime is inappropriate for this object.
# Returns NULL in all other cases.
shiny_rmd_warning <- function() {
runtime <- knitr::opts_knit$get("rmarkdown.runtime")
if (!is.null(runtime) && runtime != "shiny")
# note that the RStudio IDE checks for this specific string to detect Shiny
# applications in static document
list(structure(
"Shiny application in a static R Markdown document",
class = "rmd_warning"))
else
NULL
}
#' @rdname knitr_methods
#' @export
knit_print.shiny.appobj <- function(x, ...) {
opts <- x$options %OR% list()
width <- if (is.null(opts$width)) "100%" else opts$width
height <- if (is.null(opts$height)) "400" else opts$height
runtime <- knitr::opts_knit$get("rmarkdown.runtime")
if (!is.null(runtime) && runtime != "shiny") {
# If not rendering to a Shiny document, create a box exactly the same
# dimensions as the Shiny app would have had (so the document continues to
# flow as it would have with the app), and display a diagnostic message
width <- validateCssUnit(width)
height <- validateCssUnit(height)
output <- tags$div(
style=paste("width:", width, "; height:", height, "; text-align: center;",
"box-sizing: border-box;", "-moz-box-sizing: border-box;",
"-webkit-box-sizing: border-box;"),
class="muted well",
"Shiny applications not supported in static R Markdown documents")
}
else {
path <- addSubApp(x)
output <- deferredIFrame(path, width, height)
}
# If embedded Shiny apps ever have JS/CSS dependencies (like pym.js) we'll
# need to grab those and put them in meta, like in knit_print.shiny.tag. But
# for now it's not an issue, so just return the HTML and warning.
knitr::asis_output(htmlPreserve(format(output, indent=FALSE)),
meta = shiny_rmd_warning(), cacheable = FALSE)
}
# Let us use a nicer syntax in knitr chunks than literally
# calling output$value <- renderFoo(...) and fooOutput().
#' @rdname knitr_methods
#' @param inline Whether the object is printed inline.
#' @export
knit_print.shiny.render.function <- function(x, ..., inline = FALSE) {
x <- htmltools::as.tags(x, inline = inline)
output <- knitr::knit_print(tagList(x))
attr(output, "knit_cacheable") <- FALSE
attr(output, "knit_meta") <- append(attr(output, "knit_meta"),
shiny_rmd_warning())
output
}
# Lets us drop reactive expressions directly into a knitr chunk and have the
# value printed out! Nice for teaching if nothing else.
#' @rdname knitr_methods
#' @export
knit_print.reactive <- function(x, ..., inline = FALSE) {
renderFunc <- if (inline) renderText else renderPrint
knitr::knit_print(renderFunc({
x()
}), inline = inline)
}

611
R/bootstrap-layout.R Normal file
View File

@@ -0,0 +1,611 @@
#' Create a page with fluid layout
#'
#' Functions for creating fluid page layouts. A fluid page layout consists of
#' rows which in turn include columns. Rows exist for the purpose of making sure
#' their elements appear on the same line (if the browser has adequate width).
#' Columns exist for the purpose of defining how much horizontal space within a
#' 12-unit wide grid it's elements should occupy. Fluid pages scale their
#' components in realtime to fill all available browser width.
#'
#' @param ... Elements to include within the page
#' @param title The browser window title (defaults to the host URL of the page).
#' Can also be set as a side effect of the \code{\link{titlePanel}} function.
#' @param responsive This option is deprecated; it is no longer optional with
#' Bootstrap 3.
#' @param theme Alternative Bootstrap stylesheet (normally a css file within the
#' www directory). For example, to use the theme located at
#' \code{www/bootstrap.css} you would use \code{theme = "bootstrap.css"}.
#'
#' @return A UI defintion that can be passed to the \link{shinyUI} function.
#'
#' @details To create a fluid page use the \code{fluidPage} function and include
#' instances of \code{fluidRow} and \code{\link{column}} within it. As an
#' alternative to low-level row and column functions you can also use
#' higher-level layout functions like \code{\link{sidebarLayout}}.
#'
#' @note See the \href{http://shiny.rstudio.com/articles/layout-guide.html}{
#' Shiny-Application-Layout-Guide} for additional details on laying out fluid
#' pages.
#'
#' @seealso \code{\link{column}}, \code{\link{sidebarLayout}}
#'
#' @examples
#' shinyUI(fluidPage(
#'
#' # Application title
#' titlePanel("Hello Shiny!"),
#'
#' sidebarLayout(
#'
#' # Sidebar with a slider input
#' sidebarPanel(
#' sliderInput("obs",
#' "Number of observations:",
#' min = 0,
#' max = 1000,
#' value = 500)
#' ),
#'
#' # Show a plot of the generated distribution
#' mainPanel(
#' plotOutput("distPlot")
#' )
#' )
#' ))
#'
#' shinyUI(fluidPage(
#' title = "Hello Shiny!",
#' fluidRow(
#' column(width = 4,
#' "4"
#' ),
#' column(width = 3, offset = 2,
#' "3 offset 2"
#' )
#' )
#' ))
#'
#' @rdname fluidPage
#' @export
fluidPage <- function(..., title = NULL, responsive = NULL, theme = NULL) {
bootstrapPage(div(class = "container-fluid", ...),
title = title,
responsive = responsive,
theme = theme)
}
#' @rdname fluidPage
#' @export
fluidRow <- function(...) {
div(class = "row", ...)
}
#' Create a page with a fixed layout
#'
#' Functions for creating fixed page layouts. A fixed page layout consists of
#' rows which in turn include columns. Rows exist for the purpose of making sure
#' their elements appear on the same line (if the browser has adequate width).
#' Columns exist for the purpose of defining how much horizontal space within a
#' 12-unit wide grid it's elements should occupy. Fixed pages limit their width
#' to 940 pixels on a typical display, and 724px or 1170px on smaller and larger
#' displays respectively.
#'
#' @param ... Elements to include within the container
#' @param title The browser window title (defaults to the host URL of the page)
#' @param responsive This option is deprecated; it is no longer optional with
#' Bootstrap 3.
#' @param theme Alternative Bootstrap stylesheet (normally a css file within the
#' www directory). For example, to use the theme located at
#' \code{www/bootstrap.css} you would use \code{theme = "bootstrap.css"}.
#'
#' @return A UI defintion that can be passed to the \link{shinyUI} function.
#'
#' @details To create a fixed page use the \code{fixedPage} function and include
#' instances of \code{fixedRow} and \code{\link{column}} within it. Note that
#' unlike \code{\link{fluidPage}}, fixed pages cannot make use of higher-level
#' layout functions like \code{sidebarLayout}, rather, all layout must be done
#' with \code{fixedRow} and \code{column}.
#'
#' @note See the \href{http://shiny.rstudio.com/articles/layout-guide.html}{
#' Shiny Application Layout Guide} for additional details on laying out fixed
#' pages.
#'
#' @seealso \code{\link{column}}
#'
#' @examples
#' shinyUI(fixedPage(
#' title = "Hello, Shiny!",
#' fixedRow(
#' column(width = 4,
#' "4"
#' ),
#' column(width = 3, offset = 2,
#' "3 offset 2"
#' )
#' )
#' ))
#'
#' @rdname fixedPage
#' @export
fixedPage <- function(..., title = NULL, responsive = NULL, theme = NULL) {
bootstrapPage(div(class = "container", ...),
title = title,
responsive = responsive,
theme = theme)
}
#' @rdname fixedPage
#' @export
fixedRow <- function(...) {
div(class = "row", ...)
}
#' Create a column within a UI definition
#'
#' Create a column for use within a \code{\link{fluidRow}} or
#' \code{\link{fixedRow}}
#'
#' @param width The grid width of the column (must be between 1 and 12)
#' @param ... Elements to include within the column
#' @param offset The number of columns to offset this column from the end of the
#' previous column.
#'
#' @return A column that can be included within a
#' \code{\link{fluidRow}} or \code{\link{fixedRow}}.
#'
#'
#' @seealso \code{\link{fluidRow}}, \code{\link{fixedRow}}.
#'
#' @examples
#' fluidRow(
#' column(4,
#' sliderInput("obs", "Number of observations:",
#' min = 1, max = 1000, value = 500)
#' ),
#' column(8,
#' plotOutput("distPlot")
#' )
#' )
#'
#' fluidRow(
#' column(width = 4,
#' "4"
#' ),
#' column(width = 3, offset = 2,
#' "3 offset 2"
#' )
#' )
#' @export
column <- function(width, ..., offset = 0) {
if (!is.numeric(width) || (width < 1) || (width > 12))
stop("column width must be between 1 and 12")
colClass <- paste0("col-sm-", width)
if (offset > 0)
colClass <- paste0(colClass, " col-sm-offset-", offset)
div(class = colClass, ...)
}
#' Create a panel containing an application title.
#'
#' @param title An application title to display
#' @param windowTitle The title that should be displayed by the browser window.
#'
#' @details Calling this function has the side effect of including a
#' \code{title} tag within the head. You can also specify a page title
#' explicitly using the `title` parameter of the top-level page function.
#'
#'
#' @examples
#' titlePanel("Hello Shiny!")
#'
#' @export
titlePanel <- function(title, windowTitle=title) {
tagList(
tags$head(tags$title(windowTitle)),
h2(title)
)
}
#' Layout a sidebar and main area
#'
#' Create a layout with a sidebar and main area. The sidebar is displayed with a
#' distinct background color and typically contains input controls. The main
#' area occupies 2/3 of the horizontal width and typically contains outputs.
#'
#' @param sidebarPanel The \link{sidebarPanel} containing input controls
#' @param mainPanel The \link{mainPanel} containing outputs
#' @param position The position of the sidebar relative to the main area ("left"
#' or "right")
#' @param fluid \code{TRUE} to use fluid layout; \code{FALSE} to use fixed
#' layout.
#'
#' @examples
#' # Define UI
#' shinyUI(fluidPage(
#'
#' # Application title
#' titlePanel("Hello Shiny!"),
#'
#' sidebarLayout(
#'
#' # Sidebar with a slider input
#' sidebarPanel(
#' sliderInput("obs",
#' "Number of observations:",
#' min = 0,
#' max = 1000,
#' value = 500)
#' ),
#'
#' # Show a plot of the generated distribution
#' mainPanel(
#' plotOutput("distPlot")
#' )
#' )
#' ))
#'
#' @export
sidebarLayout <- function(sidebarPanel,
mainPanel,
position = c("left", "right"),
fluid = TRUE) {
# determine the order
position <- match.arg(position)
if (position == "left") {
firstPanel <- sidebarPanel
secondPanel <- mainPanel
}
else if (position == "right") {
firstPanel <- mainPanel
secondPanel <- sidebarPanel
}
# return as as row
if (fluid)
fluidRow(firstPanel, secondPanel)
else
fixedRow(firstPanel, secondPanel)
}
#' Lay out UI elements vertically
#'
#' Create a container that includes one or more rows of content (each element
#' passed to the container will appear on it's own line in the UI)
#'
#' @param ... Elements to include within the container
#' @param fluid \code{TRUE} to use fluid layout; \code{FALSE} to use fixed
#' layout.
#'
#' @seealso \code{\link{fluidPage}}, \code{\link{flowLayout}}
#'
#' @examples
#' shinyUI(fluidPage(
#' verticalLayout(
#' a(href="http://example.com/link1", "Link One"),
#' a(href="http://example.com/link2", "Link Two"),
#' a(href="http://example.com/link3", "Link Three")
#' )
#' ))
#' @export
verticalLayout <- function(..., fluid = TRUE) {
lapply(list(...), function(row) {
col <- column(12, row)
if (fluid)
fluidRow(col)
else
fixedRow(col)
})
}
#' Flow layout
#'
#' Lays out elements in a left-to-right, top-to-bottom arrangement. The elements
#' on a given row will be top-aligned with each other. This layout will not work
#' well with elements that have a percentage-based width (e.g.
#' \code{\link{plotOutput}} at its default setting of \code{width = "100\%"}).
#'
#' @param ... Unnamed arguments will become child elements of the layout. Named
#' arguments will become HTML attributes on the outermost tag.
#' @param cellArgs Any additional attributes that should be used for each cell
#' of the layout.
#'
#' @seealso \code{\link{verticalLayout}}
#'
#' @examples
#' flowLayout(
#' numericInput("rows", "How many rows?", 5),
#' selectInput("letter", "Which letter?", LETTERS),
#' sliderInput("value", "What value?", 0, 100, 50)
#' )
#' @export
flowLayout <- function(..., cellArgs = list()) {
children <- list(...)
childIdx <- !nzchar(names(children) %OR% character(length(children)))
attribs <- children[!childIdx]
children <- children[childIdx]
do.call(tags$div, c(list(class = "shiny-flow-layout"),
attribs,
lapply(children, function(x) {
do.call(tags$div, c(cellArgs, list(x)))
})
))
}
#' Input panel
#'
#' A \code{\link{flowLayout}} with a grey border and light grey background,
#' suitable for wrapping inputs.
#'
#' @param ... Input controls or other HTML elements.
#'
#' @export
inputPanel <- function(...) {
div(class = "shiny-input-panel",
flowLayout(...)
)
}
#' Split layout
#'
#' Lays out elements horizontally, dividing the available horizontal space into
#' equal parts (by default).
#'
#' @param ... Unnamed arguments will become child elements of the layout. Named
#' arguments will become HTML attributes on the outermost tag.
#' @param cellWidths Character or numeric vector indicating the widths of the
#' individual cells. Recycling will be used if needed. Character values will
#' be interpreted as CSS lengths (see \code{\link{validateCssUnit}}), numeric
#' values as pixels.
#' @param cellArgs Any additional attributes that should be used for each cell
#' of the layout.
#'
#' @examples
#' # Equal sizing
#' splitLayout(
#' plotOutput("plot1"),
#' plotOutput("plot2")
#' )
#'
#' # Custom widths
#' splitLayout(cellWidths = c("25%", "75%"),
#' plotOutput("plot1"),
#' plotOutput("plot2")
#' )
#'
#' # All cells at 300 pixels wide, with cell padding
#' # and a border around everything
#' splitLayout(
#' style = "border: 1px solid silver;",
#' cellWidths = 300,
#' cellArgs = list(style = "padding: 6px"),
#' plotOutput("plot1"),
#' plotOutput("plot2"),
#' plotOutput("plot3")
#' )
#' @export
splitLayout <- function(..., cellWidths = NULL, cellArgs = list()) {
children <- list(...)
childIdx <- !nzchar(names(children) %OR% character(length(children)))
attribs <- children[!childIdx]
children <- children[childIdx]
count <- length(children)
if (length(cellWidths) == 0 || is.na(cellWidths)) {
cellWidths <- sprintf("%.3f%%", 100 / count)
}
cellWidths <- rep(cellWidths, length.out = count)
cellWidths <- sapply(cellWidths, validateCssUnit)
do.call(tags$div, c(list(class = "shiny-split-layout"),
attribs,
mapply(children, cellWidths, FUN = function(x, w) {
do.call(tags$div, c(
list(style = sprintf("width: %s;", w)),
cellArgs,
list(x)
))
}, SIMPLIFY = FALSE)
))
}
#' Flex Box-based row/column layouts
#'
#' Creates row and column layouts with proportionally-sized cells, using the
#' Flex Box layout model of CSS3. These can be nested to create arbitrary
#' proportional-grid layouts. \strong{Warning:} Flex Box is not well supported
#' by Internet Explorer, so these functions should only be used where modern
#' browsers can be assumed.
#'
#' @details If you try to use \code{fillRow} and \code{fillCol} inside of other
#' Shiny containers, such as \code{\link{sidebarLayout}},
#' \code{\link{navbarPage}}, or even \code{tags$div}, you will probably find
#' that they will not appear. This is due to \code{fillRow} and \code{fillCol}
#' defaulting to \code{height="100\%"}, which will only work inside of
#' containers that have determined their own size (rather than shrinking to
#' the size of their contents, as is usually the case in HTML).
#'
#' To avoid this problem, you have two options:
#' \itemize{
#' \item only use \code{fillRow}/\code{fillCol} inside of \code{fillPage},
#' \code{fillRow}, or \code{fillCol}
#' \item provide an explicit \code{height} argument to
#' \code{fillRow}/\code{fillCol}
#' }
#'
#' @param ... UI objects to put in each row/column cell; each argument will
#' occupy a single cell. (To put multiple items in a single cell, you can use
#' \code{\link{tagList}} or \code{\link{div}} to combine them.) Named
#' arguments will be used as attributes on the \code{div} element that
#' encapsulates the row/column.
#' @param flex Determines how space should be distributed to the cells. Can be a
#' single value like \code{1} or \code{2} to evenly distribute the available
#' space; or use a vector of numbers to specify the proportions. For example,
#' \code{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
#' entire row/column. For the default height of \code{"100\%"} to be
#' effective, the parent must be \code{fillPage}, another
#' \code{fillRow}/\code{fillCol}, or some other HTML element whose height is
#' not determined by the height of its contents.
#'
#' @examples
#' \donttest{
#' # Only run this example in interactive R sessions.
#' # NOTE: This example should be run with example(fillRow, ask = FALSE) to
#' # avoid being prompted to hit Enter during plot rendering.
#' if (interactive()) {
#'
#' ui <- fillPage(fillRow(
#' plotOutput("plotLeft", height = "100%"),
#' fillCol(
#' plotOutput("plotTopRight", height = "100%"),
#' plotOutput("plotBottomRight", height = "100%")
#' )
#' ))
#'
#' server <- function(input, output, session) {
#' output$plotLeft <- renderPlot(plot(cars))
#' output$plotTopRight <- renderPlot(plot(pressure))
#' output$plotBottomRight <- renderPlot(plot(AirPassengers))
#' }
#'
#' shinyApp(ui, server)
#'
#' }
#' }
#' @export
fillRow <- function(..., flex = 1, width = "100%", height = "100%") {
flexfill(..., direction = "row", flex = flex, width = width, height = height)
}
#' @rdname fillRow
#' @export
fillCol <- function(..., flex = 1, width = "100%", height = "100%") {
flexfill(..., direction = "column", flex = flex, width = width, height = height)
}
flexfill <- function(..., direction, flex, width = width, height = height) {
children <- list(...)
attrs <- list()
if (!is.null(names(children))) {
attrs <- children[names(children) != ""]
children <- children[names(children) == ""]
}
if (length(flex) > length(children)) {
flex <- flex[1:length(children)]
}
# The dimension along the main axis
main <- switch(direction,
row = "width",
"row-reverse" = "width",
column = "height",
"column-reverse" = "height",
stop("Unexpected direction")
)
# The dimension along the cross axis
cross <- if (main == "width") "height" else "width"
divArgs <- list(
class = sprintf("flexfill-container flexfill-container-%s", direction),
style = css(
display = "-webkit-flex",
display = "-ms-flexbox",
display = "flex",
flex.direction = direction,
width = validateCssUnit(width),
height = validateCssUnit(height)
),
mapply(children, flex, FUN = function(el, flexValue) {
if (is.na(flexValue)) {
# If the flex value is NA, then put the element in a simple flex item
# that sizes itself (along the main axis) to its contents
tags$div(
class = "flexfill-item",
style = css(
position = "relative",
"-webkit-flex" = "none",
"-ms-flex" = "none",
flex = "none"
),
style = paste0(main, ":auto;", cross, ":100%;"),
el
)
} else if (is.numeric(flexValue)) {
# If the flex value is numeric, we need *two* wrapper divs. The outer is
# the flex item, and the inner is an absolute-fill div that is needed to
# make percentage-based sizing for el work correctly. I don't understand
# why this is needed but the truth is probably in this SO page:
# http://stackoverflow.com/questions/15381172/css-flexbox-child-height-100
tags$div(
class = "flexfill-item",
style = css(
position = "relative",
"-webkit-flex" = flexValue,
"-ms-flex" = flexValue,
flex = flexValue,
width = "100%", height = "100%"
),
tags$div(
class = "flexfill-item-inner",
style = css(
position = "absolute",
top = 0, left = 0, right = 0, bottom = 0
),
el
)
)
} else {
stop("Unexpected flex argument: ", flexValue)
}
}, SIMPLIFY = FALSE, USE.NAMES = FALSE)
)
do.call(tags$div, c(attrs, divArgs))
}
css <- function(..., collapse_ = "") {
props <- list(...)
if (length(props) == 0) {
return("")
}
if (is.null(names(props)) || any(names(props) == "")) {
stop("cssList expects all arguments to be named")
}
# Necessary to make factors show up as level names, not numbers
props[] <- lapply(props, paste, collapse = " ")
# Drop null args
props <- props[!sapply(props, empty)]
if (length(props) == 0) {
return("")
}
# Replace all '.' and '_' in property names to '-'
names(props) <- gsub("[._]", "-", tolower(gsub("([A-Z])", "-\\1", names(props))))
# Create "!important" suffix for each property whose name ends with !, then
# remove the ! from the property name
important <- ifelse(grepl("!$", names(props), perl = TRUE), " !important", "")
names(props) <- sub("!$", "", names(props), perl = TRUE)
paste0(names(props), ":", props, important, ";", collapse = collapse_)
}
empty <- function(x) {
length(x) == 0 || (is.character(x) && !any(nzchar(x)))
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,29 +1,26 @@
# A context object for tracking a cache that needs to be dirtied when a set of
# files changes on disk. Each time the cache is dirtied, the set of files is
# A context object for tracking a cache that needs to be dirtied when a set of
# files changes on disk. Each time the cache is dirtied, the set of files is
# cleared. Therefore, the set of files needs to be re-built each time the cached
# code executes. This approach allows for dynamic dependency graphs.
CacheContext <- setRefClass(
CacheContext <- R6Class(
'CacheContext',
fields = list(
.dirty = 'logical',
.tests = 'list'
),
methods = list(
initialize = function() {
.dirty <<- TRUE
# List of functions that return TRUE if dirty
.tests <<- list()
},
portable = FALSE,
class = FALSE,
public = list(
.dirty = TRUE,
# List of functions that return TRUE if dirty
.tests = list(),
addDependencyFile = function(file) {
if (.dirty)
return()
file <- normalizePath(file)
mtime <- file.info(file)$mtime
.tests <<- c(.tests, function() {
newMtime <- try(file.info(file)$mtime, silent=TRUE)
if (is(newMtime, 'try-error'))
if (inherits(newMtime, 'try-error'))
return(TRUE)
return(!identical(mtime, newMtime))
})
@@ -37,14 +34,14 @@ CacheContext <- setRefClass(
isDirty = function() {
if (.dirty)
return(TRUE)
for (test in .tests) {
if (test()) {
forceDirty()
return(TRUE)
}
}
return(FALSE)
},
reset = function() {
@@ -53,9 +50,9 @@ CacheContext <- setRefClass(
},
with = function(func) {
oldCC <- .currentCacheContext$cc
.currentCacheContext$cc <- .self
.currentCacheContext$cc <- self
on.exit(.currentCacheContext$cc <- oldCC)
return(func())
}
)
@@ -63,18 +60,18 @@ CacheContext <- setRefClass(
.currentCacheContext <- new.env()
# Indicates to Shiny that the given file path is part of the dependency graph
# Indicates to Shiny that the given file path is part of the dependency graph
# for whatever is currently executing (so far, only ui.R). By default, ui.R only
# gets re-executed when it is detected to have changed; this function allows the
# caller to indicate that it should also re-execute if the given file changes.
#
#
# If NULL or NA is given as the argument, then ui.R will re-execute next time.
dependsOnFile <- function(filepath) {
if (is.null(.currentCacheContext$cc))
return()
if (is.null(filepath) || is.na(filepath))
.currentCacheContext$cc$forceDirty()
else
.currentCacheContext$cc$addDependencyFile(filepath)
}
}

333
R/conditions.R Normal file
View File

@@ -0,0 +1,333 @@
#' Stack trace manipulation functions
#'
#' Advanced (borderline internal) functions for capturing, printing, and
#' manipulating stack traces.
#'
#' @return \code{printError} and \code{printStackTrace} return
#' \code{invisible()}. The other functions pass through the results of
#' \code{expr}.
#'
#' @examples
#' # Keeps tryCatch and withVisible related calls off the
#' # pretty-printed stack trace
#'
#' visibleFunction1 <- function() {
#' stop("Kaboom!")
#' }
#'
#' visibleFunction2 <- function() {
#' visibleFunction1()
#' }
#'
#' hiddenFunction <- function(expr) {
#' expr
#' }
#'
#' # An example without ..stacktraceon/off.. manipulation.
#' # The outer "try" is just to prevent example() from stopping.
#' try({
#' # The withLogErrors call ensures that stack traces are captured
#' # and that errors that bubble up are logged using warning().
#' withLogErrors({
#' # tryCatch and withVisible are just here to add some noise to
#' # the stack trace.
#' tryCatch(
#' withVisible({
#' hiddenFunction(visibleFunction2())
#' })
#' )
#' })
#' })
#'
#' # Now the same example, but with ..stacktraceon/off.. to hide some
#' # of the less-interesting bits (tryCatch and withVisible).
#' ..stacktraceoff..({
#' try({
#' withLogErrors({
#' tryCatch(
#' withVisible(
#' hiddenFunction(
#' ..stacktraceon..(visibleFunction2())
#' )
#' )
#' )
#' })
#' })
#' })
#'
#'
#' @name stacktrace
#' @rdname stacktrace
#' @keywords internal
NULL
getCallNames <- function(calls) {
sapply(calls, function(call) {
if (is.function(call[[1]])) {
"<Anonymous>"
} else if (inherits(call[[1]], "call")) {
paste0(format(call[[1]]), collapse = " ")
} else if (typeof(call[[1]]) == "promise") {
"<Promise>"
} else {
paste0(as.character(call[[1]]), collapse = " ")
}
})
}
getLocs <- function(calls) {
sapply(calls, function(call) {
srcref <- attr(call, "srcref", exact = TRUE)
if (!is.null(srcref)) {
srcfile <- attr(srcref, "srcfile", exact = TRUE)
if (!is.null(srcfile) && !is.null(srcfile$filename)) {
loc <- paste0(srcfile$filename, "#", srcref[[1]])
return(paste0(" [", loc, "]"))
}
}
return("")
})
}
#' @details \code{captureStackTraces} runs the given \code{expr} and if any
#' \emph{uncaught} errors occur, annotates them with stack trace info for use
#' by \code{printError} and \code{printStackTrace}. It is not necessary to use
#' \code{captureStackTraces} around the same expression as
#' \code{withLogErrors}, as the latter includes a call to the former. Note
#' that if \code{expr} contains calls (either directly or indirectly) to
#' \code{try}, or \code{tryCatch} with an error handler, stack traces therein
#' cannot be captured unless another \code{captureStackTraces} call is
#' inserted in the interior of the \code{try} or \code{tryCatch}. This is
#' because these calls catch the error and prevent it from traveling up to the
#' condition handler installed by \code{captureStackTraces}.
#'
#' @param expr The expression to wrap.
#' @rdname stacktrace
#' @export
captureStackTraces <- function(expr) {
withCallingHandlers(expr,
error = function(e) {
if (is.null(attr(e, "stack.trace", exact = TRUE))) {
calls <- sys.calls()
attr(e, "stack.trace") <- calls
stop(e)
}
}
)
}
#' @details \code{withLogErrors} captures stack traces and logs errors that
#' occur in \code{expr}, but does allow errors to propagate beyond this point
#' (i.e. it doesn't catch the error). The same caveats that apply to
#' \code{captureStackTraces} with regard to \code{try}/\code{tryCatch} apply
#' to \code{withLogErrors}.
#' @rdname stacktrace
#' @export
withLogErrors <- function(expr,
full = getOption("shiny.fullstacktrace", FALSE),
offset = getOption("shiny.stacktraceoffset", TRUE)) {
withCallingHandlers(
captureStackTraces(expr),
error = function(cond) {
# Don't print shiny.silent.error (i.e. validation errors)
if (inherits(cond, "shiny.silent.error"))
return()
printError(cond, full = full, offset = offset)
}
)
}
#' @details \code{printError} prints the error and stack trace (if any) using
#' \code{warning(immediate.=TRUE)}. \code{printStackTrace} prints the stack
#' trace only.
#'
#' @param cond An condition object (generally, an error).
#' @param full If \code{TRUE}, then every element of \code{sys.calls()} will be
#' included in the stack trace. By default (\code{FALSE}), calls that Shiny
#' deems uninteresting will be hidden.
#' @param offset If \code{TRUE} (the default), srcrefs will be reassigned from
#' the calls they originated from, to the destinations of those calls. If
#' you're used to stack traces from other languages, this feels more
#' intuitive, as the definition of the function indicated in the call and the
#' location specified by the srcref match up. If \code{FALSE}, srcrefs will be
#' left alone (traditional R treatment where the srcref is of the callsite).
#' @rdname stacktrace
#' @export
printError <- function(cond,
full = getOption("shiny.fullstacktrace", FALSE),
offset = getOption("shiny.stacktraceoffset", TRUE)) {
warning(call. = FALSE, immediate. = TRUE, sprintf("Error in %s: %s",
getCallNames(list(conditionCall(cond))), conditionMessage(cond)))
printStackTrace(cond, full = full, offset = offset)
invisible()
}
#' @rdname stacktrace
#' @export
printStackTrace <- function(cond,
full = getOption("shiny.fullstacktrace", FALSE),
offset = getOption("shiny.stacktraceoffset", TRUE)) {
stackTrace <- attr(cond, "stack.trace", exact = TRUE)
tryCatch(
if (!is.null(stackTrace)) {
message(paste0(
"Stack trace (innermost first):\n",
paste0(collapse = "\n",
formatStackTrace(stackTrace, full = full, offset = offset,
indent = " ")
)
))
} else {
message("No stack trace available")
},
error = function(cond) {
warning("Failed to write stack trace: ", cond)
}
)
invisible()
}
#' @details \code{extractStackTrace} takes a list of calls (e.g. as returned
#' from \code{conditionStackTrace(cond)}) and returns a data frame with one
#' row for each stack frame and the columns \code{num} (stack frame number),
#' \code{call} (a function name or similar), and \code{loc} (source file path
#' and line number, if available).
#' @rdname stacktrace
#' @export
extractStackTrace <- function(calls,
full = getOption("shiny.fullstacktrace", FALSE),
offset = getOption("shiny.stacktraceoffset", TRUE)) {
srcrefs <- getSrcRefs(calls)
if (offset) {
# Offset calls vs. srcrefs by 1 to make them more intuitive.
# E.g. for "foo [bar.R:10]", line 10 of bar.R will be part of
# the definition of foo().
srcrefs <- c(utils::tail(srcrefs, -1), list(NULL))
}
calls <- setSrcRefs(calls, srcrefs)
callnames <- getCallNames(calls)
# Hide and show parts of the callstack based on ..stacktrace(on|off)..
if (full) {
toShow <- rep.int(TRUE, length(calls))
} else {
# Remove stop(), .handleSimpleError(), and h() calls from the end of
# the calls--they don't add any helpful information. But only remove
# the last *contiguous* block of them, and then, only if they are the
# last thing in the calls list.
hideable <- callnames %in% c("stop", ".handleSimpleError", "h")
# What's the last that *didn't* match stop/.handleSimpleError/h?
lastGoodCall <- max(which(!hideable))
toRemove <- length(calls) - lastGoodCall
# But don't remove more than 5 levels--that's an indication we might
# have gotten it wrong, I guess
if (toRemove > 0 && toRemove < 5) {
calls <- utils::head(calls, -toRemove)
callnames <- utils::head(callnames, -toRemove)
}
# This uses a ref-counting scheme. It might make sense to switch this
# to a toggling scheme, so the most recent ..stacktrace(on|off)..
# directive wins, regardless of what came before it.
# Also explicitly remove ..stacktraceon.. because it can appear with
# score > 0 but still should never be shown.
score <- rep.int(0, length(callnames))
score[callnames == "..stacktraceoff.."] <- -1
score[callnames == "..stacktraceon.."] <- 1
toShow <- (1 + cumsum(score)) > 0 & !(callnames %in% c("..stacktraceon..", "..stacktraceoff.."))
}
calls <- calls[toShow]
calls <- rev(calls) # Show in traceback() order
index <- rev(which(toShow))
width <- floor(log10(max(index))) + 1
data.frame(
num = index,
call = getCallNames(calls),
loc = getLocs(calls),
stringsAsFactors = FALSE
)
}
#' @details \code{formatStackTrace} is similar to \code{extractStackTrace}, but
#' it returns a preformatted character vector instead of a data frame.
#' @param indent A string to prefix every line of the stack trace.
#' @rdname stacktrace
#' @export
formatStackTrace <- function(calls, indent = " ",
full = getOption("shiny.fullstacktrace", FALSE),
offset = getOption("shiny.stacktraceoffset", TRUE)) {
st <- extractStackTrace(calls, full = full, offset = offset)
if (nrow(st) == 0) {
return(character(0))
}
width <- floor(log10(max(st$num))) + 1
paste0(
indent,
formatC(st$num, width = width),
": ",
st$call,
st$loc
)
}
getSrcRefs <- function(calls) {
lapply(calls, function(call) {
attr(call, "srcref", exact = TRUE)
})
}
setSrcRefs <- function(calls, srcrefs) {
mapply(function(call, srcref) {
structure(call, srcref = srcref)
}, calls, srcrefs)
}
stripStackTrace <- function(cond) {
conditionStackTrace(cond) <- NULL
}
#' @details \code{conditionStackTrace} and \code{conditionStackTrace<-} are
#' accessor functions for getting/setting stack traces on conditions.
#'
#' @param cond A condition that may have previously been annotated by
#' \code{captureStackTraces} (or \code{withLogErrors}).
#' @rdname stacktrace
#' @export
conditionStackTrace <- function(cond) {
attr(cond, "stack.trace", exact = TRUE)
}
#' @param value The stack trace value to assign to the condition.
#' @rdname stacktrace
#' @export
`conditionStackTrace<-` <- function(cond, value) {
attr(cond, "stack.trace") <- value
invisible(cond)
}
#' @details The two functions \code{..stacktraceon..} and
#' \code{..stacktraceoff..} have no runtime behavior during normal execution;
#' they exist only to create artifacts on the stack trace (sys.call()) that
#' instruct the stack trace pretty printer what parts of the stack trace are
#' interesting or not. The initial state is 1 and we walk from the outermost
#' call inwards. Each ..stacktraceoff.. decrements the state by one, and each
#' ..stacktraceon.. increments the state by one. Any stack trace frame whose
#' value is less than 1 is hidden, and finally, the ..stacktraceon.. and
#' ..stacktraceoff.. calls themselves are hidden too.
#'
#' @rdname stacktrace
#' @export
..stacktraceon.. <- function(expr) expr
#' @rdname stacktrace
#' @export
..stacktraceoff.. <- function(expr) expr

View File

@@ -1,37 +1,38 @@
# For HTML5-capable browsers, file uploads happen through a series of requests.
#
#
# 1. Client tells server that one or more files are about to be uploaded; the
# server responds with a "job ID" that the client should use for the rest of
# the upload.
#
#
# 2. For each file (sequentially):
# a. Client tells server the name, size, and type of the file.
# b. Client sends server a small-ish blob of data.
# c. Repeat 2b until the entire file has been uploaded.
# d. Client tells server that the current file is done.
#
#
# 3. Repeat 2 until all files have been uploaded.
#
#
# 4. Client tells server that all files have been uploaded, along with the
# input ID that this data should be associated with.
#
#
# Unfortunately this approach will not work for browsers that don't support
# HTML5 File API, but the fallback approach we would like to use (multipart
# form upload, i.e. traditional HTTP POST-based file upload) doesn't work with
# the websockets package's HTTP server at the moment.
FileUploadOperation <- setRefClass(
FileUploadOperation <- R6Class(
'FileUploadOperation',
fields = list(
.parent = 'ANY',
.id = 'character',
.files = 'data.frame',
.dir = 'character',
.currentFileInfo = 'list',
.currentFileData = 'ANY',
.pendingFileInfos = 'list'
),
methods = list(
portable = FALSE,
class = FALSE,
public = list(
.parent = NULL,
.id = character(0),
.files = data.frame(),
.dir = character(0),
.currentFileInfo = list(),
.currentFileData = NULL,
.pendingFileInfos = list(),
initialize = function(parent, id, dir, fileInfos) {
.parent <<- parent
.id <<- id
@@ -54,12 +55,12 @@ FileUploadOperation <- setRefClass(
filename <- file.path(.dir, as.character(length(.files$name)))
row <- data.frame(name=file$name, size=file$size, type=file$type,
datapath=filename, stringsAsFactors=FALSE)
if (length(.files$name) == 0)
.files <<- row
else
.files <<- rbind(.files, row)
.currentFileData <<- file(filename, open='wb')
},
fileChunk = function(rawdata) {
@@ -77,33 +78,50 @@ FileUploadOperation <- setRefClass(
)
)
FileUploadContext <- setRefClass(
#' @include map.R
FileUploadContext <- R6Class(
'FileUploadContext',
fields = list(
.basedir = 'character',
.operations = 'Map'
class = FALSE,
private = list(
basedir = character(0),
operations = 'Map',
ids = character(0) # Keep track of all ids used for file uploads
),
methods = list(
public = list(
initialize = function(dir=tempdir()) {
.basedir <<- dir
private$basedir <- dir
private$operations <- Map$new()
},
createUploadOperation = function(fileInfos) {
while (TRUE) {
id <- paste(as.raw(runif(12, min=0, max=0xFF)), collapse='')
dir <- file.path(.basedir, id)
id <- paste(as.raw(p_runif(12, min=0, max=0xFF)), collapse='')
private$ids <- c(private$ids, id)
dir <- file.path(private$basedir, id)
if (!dir.create(dir))
next
op <- FileUploadOperation$new(.self, id, dir, fileInfos)
.operations$set(id, op)
op <- FileUploadOperation$new(self, id, dir, fileInfos)
private$operations$set(id, op)
return(id)
}
},
getUploadOperation = function(jobId) {
.operations$get(jobId)
private$operations$get(jobId)
},
onJobFinished = function(jobId) {
.operations$remove(jobId)
private$operations$remove(jobId)
},
# Remove the directories containing file uploads; this is to be called when
# a session ends.
rmUploadDirs = function() {
# Make sure all_paths is underneath the tempdir()
if (!grepl(normalizePath(tempdir()), normalizePath(private$basedir), fixed = TRUE)) {
stop("Won't remove upload path ", private$basedir,
"because it is not under tempdir(): ", tempdir())
}
all_paths <- file.path(private$basedir, private$ids)
unlink(all_paths, recursive = TRUE)
}
)
)

23
R/globals.R Normal file
View File

@@ -0,0 +1,23 @@
# A scope where we can put mutable global state
.globals <- new.env(parent = emptyenv())
.onLoad <- function(libname, pkgname) {
# R's lazy-loading package scheme causes the private seed to be cached in the
# package itself, making our PRNG completely deterministic. This line resets
# the private seed during load.
withPrivateSeed(reinitializeSeed())
}
.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."
)
}
}

149
R/graph.R
View File

@@ -1,51 +1,57 @@
writeReactLog <- function(file=stdout()) {
cat(RJSONIO::toJSON(.graphEnv$log, pretty=TRUE), file=file)
writeReactLog <- function(file=stdout(), sessionToken = NULL) {
log <- .graphStack$as_list()
if (!is.null(sessionToken)) {
log <- Filter(function(x) {
is.null(x$session) || identical(x$session, sessionToken)
}, log)
}
cat(toJSON(log, pretty=TRUE), file=file)
}
#' Reactive Log Visualizer
#'
#' Provides an interactive browser-based tool for visualizing reactive
#'
#' Provides an interactive browser-based tool for visualizing reactive
#' dependencies and execution in your application.
#'
#' To use the reactive log visualizer, start with a fresh R session and
#'
#' To use the reactive log visualizer, start with a fresh R session and
#' run the command \code{options(shiny.reactlog=TRUE)}; then launch your
#' application in the usual way (e.g. using \code{\link{runApp}}). At
#' any time you can hit Ctrl+F3 (or for Mac users, Command+F3) in your
#' application in the usual way (e.g. using \code{\link{runApp}}). At
#' any time you can hit Ctrl+F3 (or for Mac users, Command+F3) in your
#' web browser to launch the reactive log visualization.
#'
#' The reactive log visualization only includes reactive activity up
#' until the time the report was loaded. If you want to see more recent
#'
#' The reactive log visualization only includes reactive activity up
#' until the time the report was loaded. If you want to see more recent
#' activity, refresh the browser.
#'
#' Note that Shiny does not distinguish between reactive dependencies
#'
#' Note that Shiny does not distinguish between reactive dependencies
#' that "belong" to one Shiny user session versus another, so the
#' visualization will include all reactive activity that has taken place
#' in the process, not just for a particular application or session.
#'
#' As an alternative to pressing Ctrl/Command+F3--for example, if you
#' are using reactives outside of the context of a Shiny
#'
#' As an alternative to pressing Ctrl/Command+F3--for example, if you
#' are using reactives outside of the context of a Shiny
#' application--you can run the \code{showReactLog} function, which will
#' generate the reactive log visualization as a static HTML file and
#' launch it in your default browser. In this case, refreshing your
#' browser will not load new activity into the report; you will need to
#' generate the reactive log visualization as a static HTML file and
#' launch it in your default browser. In this case, refreshing your
#' browser will not load new activity into the report; you will need to
#' call \code{showReactLog()} explicitly.
#'
#' For security and performance reasons, do not enable
#' \code{shiny.reactlog} in production environments. When the option is
#' enabled, it's possible for any user of your app to see at least some
#'
#' For security and performance reasons, do not enable
#' \code{shiny.reactlog} in production environments. When the option is
#' enabled, it's possible for any user of your app to see at least some
#' of the source code of your reactive expressions and observers.
#'
#'
#' @export
showReactLog <- function() {
browseURL(renderReactLog())
utils::browseURL(renderReactLog())
}
renderReactLog <- function() {
renderReactLog <- function(sessionToken = NULL) {
templateFile <- system.file('www/reactive-graph.html', package='shiny')
html <- paste(readLines(templateFile, warn=FALSE), collapse='\r\n')
tc <- textConnection(NULL, 'w')
on.exit(close(tc))
writeReactLog(tc)
writeReactLog(tc, sessionToken)
cat('\n', file=tc)
flush(tc)
html <- sub('__DATA__', paste(textConnectionValue(tc), collapse='\r\n'), html, fixed=TRUE)
@@ -54,52 +60,55 @@ renderReactLog <- function() {
return(file)
}
.graphAppend <- function(logEntry) {
if (isTRUE(getOption('shiny.reactlog', FALSE)))
.graphEnv$log <- c(.graphEnv$log, list(logEntry))
}
.graphAppend <- function(logEntry, domain = getDefaultReactiveDomain()) {
if (isTRUE(getOption('shiny.reactlog'))) {
sessionToken <- if (is.null(domain)) NULL else domain$token
.graphStack$push(c(logEntry, list(
session = sessionToken,
time = as.numeric(Sys.time())
)))
}
.graphDependsOn <- function(id, label) {
if (isTRUE(getOption('shiny.reactlog', FALSE)))
.graphAppend(list(action='dep', id=id, dependsOn=label))
}
.graphDependsOnId <- function(id, dependee) {
if (isTRUE(getOption('shiny.reactlog', FALSE)))
.graphAppend(list(action='depId', id=id, dependsOn=dependee))
}
.graphCreateContext <- function(id, label, type, prevId) {
if (isTRUE(getOption('shiny.reactlog', FALSE)))
.graphAppend(list(
action='ctx', id=id, label=paste(label, collapse='\n'), type=type, prevId=prevId
))
}
.graphEnterContext <- function(id) {
if (isTRUE(getOption('shiny.reactlog', FALSE)))
.graphAppend(list(action='enter', id=id))
}
.graphExitContext <- function(id) {
if (isTRUE(getOption('shiny.reactlog', FALSE)))
.graphAppend(list(action='exit', id=id))
}
.graphValueChange <- function(label, value) {
if (isTRUE(getOption('shiny.reactlog', FALSE))) {
.graphAppend(list(
action = 'valueChange',
id = label,
value = paste(capture.output(str(value)), collapse='\n')
))
if (!is.null(domain)) {
domain$reactlog(logEntry)
}
}
.graphInvalidate <- function(id) {
if (isTRUE(getOption('shiny.reactlog', FALSE)))
.graphAppend(list(action='invalidate', id=id))
.graphDependsOn <- function(id, label) {
.graphAppend(list(action='dep', id=id, dependsOn=label))
}
.graphEnv <- new.env()
.graphEnv$log <- list()
.graphDependsOnId <- function(id, dependee) {
.graphAppend(list(action='depId', id=id, dependsOn=dependee))
}
.graphCreateContext <- function(id, label, type, prevId, domain) {
.graphAppend(list(
action='ctx', id=id, label=paste(label, collapse='\n'),
srcref=as.vector(attr(label, "srcref")), srcfile=attr(label, "srcfile"),
type=type, prevId=prevId
), domain = domain)
}
.graphEnterContext <- function(id) {
.graphAppend(list(action='enter', id=id))
}
.graphExitContext <- function(id) {
.graphAppend(list(action='exit', id=id))
}
.graphValueChange <- function(label, value) {
.graphAppend(list(
action = 'valueChange',
id = label,
value = paste(utils::capture.output(utils::str(value)), collapse='\n')
))
}
.graphInvalidate <- function(id, domain) {
.graphAppend(list(action='invalidate', id=id), domain)
}
#' @include stack.R
.graphStack <- Stack$new()

24
R/hooks.R Normal file
View File

@@ -0,0 +1,24 @@
# Call an application hook. Application hooks are provided so that front ends
# can know when a Shiny application is running:
#
# shiny.onAppStart -- called when an application begins running
# shiny.onAppStop -- called when an appliation stops
#
# Both hooks are passed the url where the application is accessible (appUrl).
# Note that the appUrl can be NULL if the application was run on a UNIX domain
# socket rather than a TCP/IP port/
callAppHook <- function(name, appUrl) {
for (hook in getHooksList(paste0("shiny.", name)))
hook(appUrl)
}
# The value for getHook can be a single function or a list of functions,
# This function ensures that the result can always be processed as a list
getHooksList <- function(name) {
hooks <- getHook(name)
if (!is.list(hooks))
hooks <- list(hooks)
hooks
}

29
R/html-deps.R Normal file
View File

@@ -0,0 +1,29 @@
#' Create a web dependency
#'
#' Ensure that a file-based HTML dependency (from the htmltools package) can be
#' served over Shiny's HTTP server. This function works by using
#' \code{\link{addResourcePath}} to map the HTML dependency's directory to a
#' URL.
#'
#' @param dependency A single HTML dependency object, created using
#' \code{\link{htmlDependency}}. If the \code{src} value is named, then
#' \code{href} and/or \code{file} names must be present.
#'
#' @return A single HTML dependency object that has an \code{href}-named element
#' in its \code{src}.
#' @export
createWebDependency <- function(dependency) {
if (is.null(dependency))
return(NULL)
if (!inherits(dependency, "html_dependency"))
stop("Unexpected non-html_dependency type")
if (is.null(dependency$src$href)) {
prefix <- paste(dependency$name, "-", dependency$version, sep = "")
addResourcePath(prefix, dependency$src$file)
dependency$src$href <- prefix
}
return(dependency)
}

8
R/htmltools.R Normal file
View File

@@ -0,0 +1,8 @@
#' @export a br code div em h1 h2 h3 h4 h5 h6 hr HTML img p pre span strong
#' @export includeCSS includeHTML includeMarkdown includeScript includeText
#' @export is.singleton singleton
#' @export tag tagAppendAttributes tagAppendChild tagAppendChildren tagList tags tagSetChildren withTags
#' @export validateCssUnit
#' @export knit_print.html knit_print.shiny.tag knit_print.shiny.tag.list
#' @export htmlTemplate suppressDependencies
NULL

139
R/image-interact-opts.R Normal file
View File

@@ -0,0 +1,139 @@
#' Create an object representing click options
#'
#' This generates an object representing click options, to be passed as the
#' \code{click} argument of \code{\link{imageOutput}} or
#' \code{\link{plotOutput}}.
#'
#' @param id Input value name. For example, if the value is \code{"plot_click"},
#' then the click coordinates will be available as \code{input$plot_click}.
#' @param clip Should the click area be clipped to the plotting area? If FALSE,
#' then the server will receive click events even when the mouse is outside
#' the plotting area, as long as it is still inside the image.
#' @export
clickOpts <- function(id = NULL, clip = TRUE) {
if (is.null(id))
stop("id must not be NULL")
list(
id = id,
clip = clip
)
}
#' Create an object representing double-click options
#'
#' This generates an object representing dobule-click options, to be passed as
#' the \code{dblclick} argument of \code{\link{imageOutput}} or
#' \code{\link{plotOutput}}.
#'
#' @param id Input value name. For example, if the value is
#' \code{"plot_dblclick"}, then the click coordinates will be available as
#' \code{input$plot_dblclick}.
#' @param clip Should the click area be clipped to the plotting area? If FALSE,
#' then the server will receive double-click events even when the mouse is
#' outside the plotting area, as long as it is still inside the image.
#' @param delay Maximum delay (in ms) between a pair clicks for them to be
#' counted as a double-click.
#' @export
dblclickOpts <- function(id = NULL, clip = TRUE, delay = 400) {
if (is.null(id))
stop("id must not be NULL")
list(
id = id,
clip = clip,
delay = delay
)
}
#' Create an object representing hover options
#'
#' This generates an object representing hovering options, to be passed as the
#' \code{hover} argument of \code{\link{imageOutput}} or
#' \code{\link{plotOutput}}.
#'
#' @param id Input value name. For example, if the value is \code{"plot_hover"},
#' then the hover coordinates will be available as \code{input$plot_hover}.
#' @param delay How long to delay (in milliseconds) when debouncing or
#' throttling, before sending the mouse location to the server.
#' @param delayType The type of algorithm for limiting the number of hover
#' events. Use \code{"throttle"} to limit the number of hover events to one
#' every \code{delay} milliseconds. Use \code{"debounce"} to suspend events
#' while the cursor is moving, and wait until the cursor has been at rest for
#' \code{delay} milliseconds before sending an event.
#' @param clip Should the hover area be clipped to the plotting area? If FALSE,
#' then the server will receive hover events even when the mouse is outside
#' the plotting area, as long as it is still inside the image.
#' @param nullOutside If \code{TRUE} (the default), the value will be set to
#' \code{NULL} when the mouse exits the plotting area. If \code{FALSE}, the
#' value will stop changing when the cursor exits the plotting area.
#' @export
hoverOpts <- function(id = NULL, delay = 300,
delayType = c("debounce", "throttle"), clip = TRUE,
nullOutside = TRUE) {
if (is.null(id))
stop("id must not be NULL")
list(
id = id,
delay = delay,
delayType = match.arg(delayType),
clip = clip,
nullOutside = nullOutside
)
}
#' Create an object representing brushing options
#'
#' This generates an object representing brushing options, to be passed as the
#' \code{brush} argument of \code{\link{imageOutput}} or
#' \code{\link{plotOutput}}.
#'
#' @param id Input value name. For example, if the value is \code{"plot_brush"},
#' then the coordinates will be available as \code{input$plot_brush}. Multiple
#' \code{imageOutput}/\code{plotOutput} calls may share the same \code{id}
#' value; brushing one image or plot will cause any other brushes with the
#' same \code{id} to disappear.
#' @param fill Fill color of the brush.
#' @param stroke Outline color of the brush.
#' @param opacity Opacity of the brush
#' @param delay How long to delay (in milliseconds) when debouncing or
#' throttling, before sending the brush data to the server.
#' @param delayType The type of algorithm for limiting the number of brush
#' events. Use \code{"throttle"} to limit the number of brush events to one
#' every \code{delay} milliseconds. Use \code{"debounce"} to suspend events
#' while the cursor is moving, and wait until the cursor has been at rest for
#' \code{delay} milliseconds before sending an event.
#' @param clip Should the brush area be clipped to the plotting area? If FALSE,
#' then the user will be able to brush outside the plotting area, as long as
#' it is still inside the image.
#' @param direction The direction for brushing. If \code{"xy"}, the brush can be
#' drawn and moved in both x and y directions. If \code{"x"}, or \code{"y"},
#' the brush wil work horizontally or vertically.
#' @param resetOnNew When a new image is sent to the browser (via
#' \code{\link{renderImage}}), should the brush be reset? The default,
#' \code{FALSE}, is useful if you want to update the plot while keeping the
#' brush. Using \code{TRUE} is useful if you want to clear the brush whenever
#' the plot is updated.
#' @export
brushOpts <- function(id = NULL, fill = "#9cf", stroke = "#036",
opacity = 0.25, delay = 300,
delayType = c("debounce", "throttle"), clip = TRUE,
direction = c("xy", "x", "y"),
resetOnNew = FALSE) {
if (is.null(id))
stop("id must not be NULL")
list(
id = id,
fill = fill,
stroke = stroke,
opacity = opacity,
delay = delay,
delayType = match.arg(delayType),
clip = clip,
direction = match.arg(direction),
resetOnNew = resetOnNew
)
}

437
R/image-interact.R Normal file
View File

@@ -0,0 +1,437 @@
#' Find rows of data that are selected by a brush
#'
#' This function returns rows from a data frame which are under a brush used
#' with \code{\link{plotOutput}}.
#'
#' It is also possible for this function to return all rows from the input data
#' frame, but with an additional column \code{selected_}, which indicates which
#' rows of the input data frame are selected by the brush (\code{TRUE} for
#' selected, \code{FALSE} for not-selected). This is enabled by setting
#' \code{allRows=TRUE} option.
#'
#' The \code{xvar}, \code{yvar}, \code{panelvar1}, and \code{panelvar2}
#' arguments specify which columns in the data correspond to the x variable, y
#' variable, and panel variables of the plot. For example, if your plot is
#' \code{plot(x=cars$speed, y=cars$dist)}, and your brush is named
#' \code{"cars_brush"}, then you would use \code{brushedPoints(cars,
#' input$cars_brush, "speed", "dist")}.
#'
#' For plots created with ggplot2, it should not be necessary to specify the
#' column names; that information will already be contained in the brush,
#' provided that variables are in the original data, and not computed. For
#' example, with \code{ggplot(cars, aes(x=speed, y=dist)) + geom_point()}, you
#' could use \code{brushedPoints(cars, input$cars_brush)}. If, however, you use
#' a computed column, like \code{ggplot(cars, aes(x=speed/2, y=dist)) +
#' geom_point()}, then it will not be able to automatically extract column names
#' and filter on them. If you want to use this function to filter data, it is
#' recommended that you not use computed columns; instead, modify the data
#' first, and then make the plot with "raw" columns in the modified data.
#'
#' If a specified x or y column is a factor, then it will be coerced to an
#' integer vector. If it is a character vector, then it will be coerced to a
#' factor and then integer vector. This means that the brush will be considered
#' to cover a given character/factor value when it covers the center value.
#'
#' If the brush is operating in just the x or y directions (e.g., with
#' \code{brushOpts(direction = "x")}, then this function will filter out points
#' using just the x or y variable, whichever is appropriate.
#'
#' @param brush The data from a brush, such as \code{input$plot_brush}.
#' @param df A data frame from which to select rows.
#' @param xvar,yvar A string with the name of the variable on the x or y axis.
#' This must also be the name of a column in \code{df}. If absent, then this
#' function will try to infer the variable from the brush (only works for
#' ggplot2).
#' @param panelvar1,panelvar2 Each of these is a string with the name of a panel
#' variable. For example, if with ggplot2, you facet on a variable called
#' \code{cyl}, then you can use \code{"cyl"} here. However, specifying the
#' panel variable should not be necessary with ggplot2; Shiny should be able
#' to auto-detect the panel variable.
#' @param allRows If \code{FALSE} (the default) return a data frame containing
#' the selected rows. If \code{TRUE}, the input data frame will have a new
#' column, \code{selected_}, which indicates whether the row was inside the
#' brush (\code{TRUE}) or outside the brush (\code{FALSE}).
#'
#' @seealso \code{\link{plotOutput}} for example usage.
#' @export
brushedPoints <- function(df, brush, xvar = NULL, yvar = NULL,
panelvar1 = NULL, panelvar2 = NULL,
allRows = FALSE) {
if (is.null(brush)) {
if (allRows)
df$selected_ <- FALSE
else
df <- df[0, , drop = FALSE]
return(df)
}
if (is.null(brush$xmin)) {
stop("brushedPoints requires a brush object with xmin, xmax, ymin, and ymax.")
}
# Which direction(s) the brush is selecting over. Direction can be 'x', 'y',
# or 'xy'.
use_x <- grepl("x", brush$direction)
use_y <- grepl("y", brush$direction)
# Try to extract vars from brush object
xvar <- xvar %OR% brush$mapping$x
yvar <- yvar %OR% brush$mapping$y
panelvar1 <- panelvar1 %OR% brush$mapping$panelvar1
panelvar2 <- panelvar2 %OR% brush$mapping$panelvar2
# Filter out x and y values
keep_rows <- rep(TRUE, nrow(df))
if (use_x) {
if (is.null(xvar))
stop("brushedPoints: not able to automatically infer `xvar` from brush")
# Extract data values from the data frame
x <- asNumber(df[[xvar]])
keep_rows <- keep_rows & (x >= brush$xmin & x <= brush$xmax)
}
if (use_y) {
if (is.null(yvar))
stop("brushedPoints: not able to automatically infer `yvar` from brush")
y <- asNumber(df[[yvar]])
keep_rows <- keep_rows & (y >= brush$ymin & y <= brush$ymax)
}
# Find which rows are matches for the panel vars (if present)
if (!is.null(panelvar1))
keep_rows <- keep_rows & panelMatch(brush$panelvar1, df[[panelvar1]])
if (!is.null(panelvar2))
keep_rows <- keep_rows & panelMatch(brush$panelvar2, df[[panelvar2]])
if (allRows) {
df$selected_ <- keep_rows
df
} else {
df[keep_rows, , drop = FALSE]
}
}
# The `brush` data structure will look something like the examples below.
# For base graphics, `mapping` is empty, and there are no panelvars:
# List of 8
# $ xmin : num 3.73
# $ xmax : num 4.22
# $ ymin : num 13.9
# $ ymax : num 19.8
# $ mapping: Named list()
# $ domain :List of 4
# ..$ left : num 1.36
# ..$ right : num 5.58
# ..$ bottom: num 9.46
# ..$ top : num 34.8
# $ range :List of 4
# ..$ left : num 58
# ..$ right : num 429
# ..$ bottom: num 226
# ..$ top : num 58
# $ log :List of 2
# ..$ x: NULL
# ..$ y: NULL
# $ direction: chr "y"
#
# For ggplot2, the mapping vars usually will be included, and if faceting is
# used, they will be listed as panelvars:
# List of 10
# $ xmin : num 3.18
# $ xmax : num 3.78
# $ ymin : num 17.1
# $ ymax : num 20.4
# $ panelvar1: int 6
# $ panelvar2: int 0
# $ mapping :List of 4
# ..$ x : chr "wt"
# ..$ y : chr "mpg"
# ..$ panelvar1: chr "cyl"
# ..$ panelvar2: chr "am"
# $ domain :List of 4
# ..$ left : num 1.32
# ..$ right : num 5.62
# ..$ bottom: num 9.22
# ..$ top : num 35.1
# $ range :List of 4
# ..$ left : num 172
# ..$ right : num 300
# ..$ bottom: num 144
# ..$ top : num 28.5
# $ log :List of 2
# ..$ x: NULL
# ..$ y: NULL
# $ direction: chr "y"
#'Find rows of data that are near a click/hover/double-click
#'
#'This function returns rows from a data frame which are near a click, hover, or
#'double-click, when used with \code{\link{plotOutput}}. The rows will be sorted
#'by their distance to the mouse event.
#'
#'It is also possible for this function to return all rows from the input data
#'frame, but with an additional column \code{selected_}, which indicates which
#'rows of the input data frame are selected by the brush (\code{TRUE} for
#'selected, \code{FALSE} for not-selected). This is enabled by setting
#'\code{allRows=TRUE} option. If this is used, the resulting data frame will not
#'be sorted by distance to the mouse event.
#'
#'The \code{xvar}, \code{yvar}, \code{panelvar1}, and \code{panelvar2} arguments
#'specify which columns in the data correspond to the x variable, y variable,
#'and panel variables of the plot. For example, if your plot is
#'\code{plot(x=cars$speed, y=cars$dist)}, and your click variable is named
#'\code{"cars_click"}, then you would use \code{nearPoints(cars,
#'input$cars_brush, "speed", "dist")}.
#'
#'@inheritParams brushedPoints
#'@param coordinfo The data from a mouse event, such as \code{input$plot_click}.
#'@param threshold A maxmimum distance to the click point; rows in the data
#' frame where the distance to the click is less than \code{threshold} will be
#' returned.
#'@param maxpoints Maximum number of rows to return. If NULL (the default),
#' return all rows that are within the threshold distance.
#'@param addDist If TRUE, add a column named \code{dist_} that contains the
#' distance from the coordinate to the point, in pixels. When no mouse event
#' has yet occured, the value of \code{dist_} will be \code{NA}.
#'@param allRows If \code{FALSE} (the default) return a data frame containing
#' the selected rows. If \code{TRUE}, the input data frame will have a new
#' column, \code{selected_}, which indicates whether the row was inside the
#' selected by the mouse event (\code{TRUE}) or not (\code{FALSE}).
#'
#'@seealso \code{\link{plotOutput}} for more examples.
#'
#' @examples
#' \dontrun{
#' # Note that in practice, these examples would need to go in reactives
#' # or observers.
#'
#' # This would select all points within 5 pixels of the click
#' nearPoints(mtcars, input$plot_click)
#'
#' # Select just the nearest point within 10 pixels of the click
#' nearPoints(mtcars, input$plot_click, threshold = 10, maxpoints = 1)
#'
#' }
#'@export
nearPoints <- function(df, coordinfo, xvar = NULL, yvar = NULL,
panelvar1 = NULL, panelvar2 = NULL,
threshold = 5, maxpoints = NULL, addDist = FALSE,
allRows = FALSE) {
if (is.null(coordinfo)) {
if (addDist)
df$dist_ <- NA_real_
if (allRows)
df$selected_ <- FALSE
else
df <- df[0, , drop = FALSE]
return(df)
}
if (is.null(coordinfo$x)) {
stop("nearPoints requires a click/hover/double-click object with x and y values.")
}
# Try to extract vars from coordinfo object
xvar <- xvar %OR% coordinfo$mapping$x
yvar <- yvar %OR% coordinfo$mapping$y
panelvar1 <- panelvar1 %OR% coordinfo$mapping$panelvar1
panelvar2 <- panelvar2 %OR% coordinfo$mapping$panelvar2
if (is.null(xvar))
stop("nearPoints: not able to automatically infer `xvar` from coordinfo")
if (is.null(yvar))
stop("nearPoints: not able to automatically infer `yvar` from coordinfo")
# Extract data values from the data frame
x <- asNumber(df[[xvar]])
y <- asNumber(df[[yvar]])
# Get the pixel coordinates of the point
coordPx <- scaleCoords(coordinfo$x, coordinfo$y, coordinfo)
# Get pixel coordinates of data points
dataPx <- scaleCoords(x, y, coordinfo)
# Distances of data points to coordPx
dists <- sqrt((dataPx$x - coordPx$x) ^ 2 + (dataPx$y - coordPx$y) ^ 2)
if (addDist)
df$dist_ <- dists
keep_rows <- (dists <= threshold)
# Find which rows are matches for the panel vars (if present)
if (!is.null(panelvar1))
keep_rows <- keep_rows & panelMatch(coordinfo$panelvar1, df[[panelvar1]])
if (!is.null(panelvar2))
keep_rows <- keep_rows & panelMatch(coordinfo$panelvar2, df[[panelvar2]])
# Track the indices to keep
keep_idx <- which(keep_rows)
# Order by distance
dists <- dists[keep_idx]
keep_idx <- keep_idx[order(dists)]
# Keep max number of rows
if (!is.null(maxpoints) && length(keep_idx) > maxpoints) {
keep_idx <- keep_idx[seq_len(maxpoints)]
}
if (allRows) {
# Add selected_ column if needed
df$selected_ <- FALSE
df$selected_[keep_idx] <- TRUE
} else {
# If we don't keep all rows, return just the selected rows, sorted by
# distance.
df <- df[keep_idx, , drop = FALSE]
}
df
}
# The coordinfo data structure will look something like the examples below.
# For base graphics, `mapping` is empty, and there are no panelvars:
# List of 7
# $ x : num 4.37
# $ y : num 12
# $ mapping: Named list()
# $ domain :List of 4
# ..$ left : num 1.36
# ..$ right : num 5.58
# ..$ bottom: num 9.46
# ..$ top : num 34.8
# $ range :List of 4
# ..$ left : num 58
# ..$ right : num 429
# ..$ bottom: num 226
# ..$ top : num 58
# $ log :List of 2
# ..$ x: NULL
# ..$ y: NULL
# $ .nonce : num 0.343
#
# For ggplot2, the mapping vars usually will be included, and if faceting is
# used, they will be listed as panelvars:
# List of 9
# $ x : num 3.78
# $ y : num 17.1
# $ panelvar1: int 6
# $ panelvar2: int 0
# $ mapping :List of 4
# ..$ x : chr "wt"
# ..$ y : chr "mpg"
# ..$ panelvar1: chr "cyl"
# ..$ panelvar2: chr "am"
# $ domain :List of 4
# ..$ left : num 1.32
# ..$ right : num 5.62
# ..$ bottom: num 9.22
# ..$ top : num 35.1
# $ range :List of 4
# ..$ left : num 172
# ..$ right : num 300
# ..$ bottom: num 144
# ..$ top : num 28.5
# $ log :List of 2
# ..$ x: NULL
# ..$ y: NULL
# $ .nonce : num 0.603
# Coerce various types of variables to numbers. This works for Date, POSIXt,
# characters, and factors. Used because the mouse coords are numeric.
asNumber <- function(x) {
if (is.character(x)) x <- as.factor(x)
if (is.factor(x)) x <- as.integer(x)
as.numeric(x)
}
# Given a panelvar value and a vector x, return logical vector indicating which
# items match the panelvar value. Because the panelvar value is always a
# string but the vector could be numeric, it might be necessary to coerce the
# panelvar to a number before comparing to the vector.
panelMatch <- function(search_value, x) {
if (is.numeric(x)) search_value <- as.numeric(search_value)
x == search_value
}
# ----------------------------------------------------------------------------
# Scaling functions
# These functions have direct analogs in Javascript code, except these are
# vectorized for x and y.
# Map a value x from a domain to a range. If clip is true, clip it to the
# range.
mapLinear <- function(x, domainMin, domainMax, rangeMin, rangeMax, clip = TRUE) {
factor <- (rangeMax - rangeMin) / (domainMax - domainMin)
val <- x - domainMin
newval <- (val * factor) + rangeMin
if (clip) {
maxval <- max(rangeMax, rangeMin)
minval <- min(rangeMax, rangeMin)
newval[newval > maxval] <- maxval
newval[newval < minval] <- minval
}
newval
}
# Scale val from domain to range. If logbase is present, use log scaling.
scale1D <- function(val, domainMin, domainMax, rangeMin, rangeMax,
logbase = NULL, clip = TRUE) {
if (!is.null(logbase))
val <- log(val, logbase)
mapLinear(val, domainMin, domainMax, rangeMin, rangeMax, clip)
}
# Inverse scale val, from range to domain. If logbase is present, use inverse
# log (power) transformation.
scaleInv1D <- function(val, domainMin, domainMax, rangeMin, rangeMax,
logbase = NULL, clip = TRUE) {
res <- mapLinear(val, rangeMin, rangeMax, domainMin, domainMax, clip)
if (!is.null(logbase))
res <- logbase ^ res
res
}
# Scale x and y coordinates from domain to range, using information in
# scaleinfo. scaleinfo must contain items $domain, $range, and $log. The
# scaleinfo object corresponds to one element from the coordmap object generated
# by getPrevPlotCoordmap or getGgplotCoordmap; it is the scaling information for
# one panel in a plot.
scaleCoords <- function(x, y, scaleinfo) {
if (is.null(scaleinfo))
return(NULL)
domain <- scaleinfo$domain
range <- scaleinfo$range
log <- scaleinfo$log
list(
x = scale1D(x, domain$left, domain$right, range$left, range$right, log$x),
y = scale1D(y, domain$bottom, domain$top, range$bottom, range$top, log$y)
)
}
# Inverse scale x and y coordinates from range to domain, using information in
# scaleinfo.
scaleInvCoords <- function(x, y, scaleinfo) {
if (is.null(scaleinfo))
return(NULL)
domain <- scaleinfo$domain
range <- scaleinfo$range
log <- scaleinfo$log
list(
x = scaleInv1D(x, domain$left, domain$right, range$left, range$right, log$x),
y = scaleInv1D(y, domain$bottom, domain$top, range$bottom, range$top, log$y)
)
}

View File

@@ -33,23 +33,31 @@ plotPNG <- function(func, filename=tempfile(fileext='.png'),
# Otherwise, if the Cairo package is installed, use CairoPNG().
# Finally, if neither quartz nor Cairo, use png().
if (capabilities("aqua")) {
pngfun <- png
} else if (getOption('shiny.usecairo', TRUE) &&
pngfun <- grDevices::png
} else if ((getOption('shiny.usecairo') %OR% TRUE) &&
nchar(system.file(package = "Cairo"))) {
# Workaround for issue #140: Cairo ignores res and dpi settings. Need to
# use regular png function.
if (res == 72) {
pngfun <- Cairo::CairoPNG
} else {
pngfun <- png
}
pngfun <- Cairo::CairoPNG
} else {
pngfun <- png
pngfun <- grDevices::png
}
pngfun(filename=filename, width=width, height=height, res=res, ...)
dv <- dev.cur()
tryCatch(shinyCallingHandlers(func()), finally = dev.off(dv))
# Call plot.new() so that even if no plotting operations are performed at
# least we have a blank background. N.B. we need to set the margin to 0
# temporarily before plot.new() because when the plot size is small (e.g.
# 200x50), we will get an error "figure margin too large", which is triggered
# by plot.new() with the default (large) margin. However, this does not
# guarantee user's code in func() will not trigger the error -- they may have
# to set par(mar = smaller_value) before they draw base graphics.
op <- graphics::par(mar = rep(0, 4))
tryCatch(
graphics::plot.new(),
finally = graphics::par(op)
)
dv <- grDevices::dev.cur()
on.exit(grDevices::dev.off(dv), add = TRUE)
func()
filename
}

51
R/input-action.R Normal file
View File

@@ -0,0 +1,51 @@
#' Action button/link
#'
#' Creates an action button or link whose value is initially zero, and increments by one
#' each time it is pressed.
#'
#' @inheritParams textInput
#' @param label The contents of the button or link--usually a text label, but
#' you could also use any other HTML, like an image.
#' @param icon An optional \code{\link{icon}} to appear on the button.
#' @param ... Named attributes to be applied to the button or link.
#'
#' @family input elements
#' @examples
#' \dontrun{
#' # In server.R
#' output$distPlot <- renderPlot({
#' # Take a dependency on input$goButton
#' input$goButton
#'
#' # Use isolate() to avoid dependency on input$obs
#' dist <- isolate(rnorm(input$obs))
#' hist(dist)
#' })
#'
#' # In ui.R
#' actionButton("goButton", "Go!")
#' }
#'
#' @seealso \code{\link{observeEvent}} and \code{\link{eventReactive}}
#'
#' @export
actionButton <- function(inputId, label, icon = NULL, width = NULL, ...) {
tags$button(id=inputId,
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
type="button",
class="btn btn-default action-button",
list(icon, label),
...
)
}
#' @rdname actionButton
#' @export
actionLink <- function(inputId, label, icon = NULL, ...) {
tags$a(id=inputId,
href="#",
class="action-button",
list(icon, label),
...
)
}

26
R/input-checkbox.R Normal file
View File

@@ -0,0 +1,26 @@
#' Checkbox Input Control
#'
#' Create a checkbox that can be used to specify logical values.
#'
#' @inheritParams textInput
#' @param value Initial value (\code{TRUE} or \code{FALSE}).
#' @return A checkbox control that can be added to a UI definition.
#'
#' @family input elements
#' @seealso \code{\link{checkboxGroupInput}}, \code{\link{updateCheckboxInput}}
#'
#' @examples
#' checkboxInput("outliers", "Show outliers", FALSE)
#' @export
checkboxInput <- function(inputId, label, value = FALSE, width = NULL) {
inputTag <- tags$input(id = inputId, type="checkbox")
if (!is.null(value) && value)
inputTag$attribs$checked <- "checked"
div(class = "form-group shiny-input-container",
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
div(class = "checkbox",
tags$label(inputTag, tags$span(label))
)
)
}

45
R/input-checkboxgroup.R Normal file
View File

@@ -0,0 +1,45 @@
#' Checkbox Group Input Control
#'
#' 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.
#'
#' @inheritParams textInput
#' @param choices List of values to show checkboxes for. If elements of the list
#' are named then that name rather than the value is displayed to the user.
#' @param selected The values that should be initially selected, if any.
#' @param inline If \code{TRUE}, render the choices inline (i.e. horizontally)
#' @return A list of HTML elements that can be added to a UI definition.
#'
#' @family input elements
#' @seealso \code{\link{checkboxInput}}, \code{\link{updateCheckboxGroupInput}}
#'
#' @examples
#' checkboxGroupInput("variable", "Variable:",
#' c("Cylinders" = "cyl",
#' "Transmission" = "am",
#' "Gears" = "gear"))
#'
#' @export
checkboxGroupInput <- function(inputId, label, choices, selected = NULL,
inline = FALSE, width = NULL) {
# resolve names
choices <- choicesWithNames(choices)
if (!is.null(selected))
selected <- validateSelected(selected, choices, inputId)
options <- generateOptions(inputId, choices, selected, inline)
divClass <- "form-group shiny-input-checkboxgroup shiny-input-container"
if (inline)
divClass <- paste(divClass, "shiny-input-container-inline")
# return label and select tag
tags$div(id = inputId,
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
class = divClass,
controlLabel(inputId, label),
options
)
}

102
R/input-date.R Normal file
View File

@@ -0,0 +1,102 @@
#' Create date input
#'
#' Creates a text input which, when clicked on, brings up a calendar that
#' the user can click on to select dates.
#'
#' The date \code{format} string specifies how the date will be displayed in
#' the browser. It allows the following values:
#'
#' \itemize{
#' \item \code{yy} Year without century (12)
#' \item \code{yyyy} Year with century (2012)
#' \item \code{mm} Month number, with leading zero (01-12)
#' \item \code{m} Month number, without leading zero (01-12)
#' \item \code{M} Abbreviated month name
#' \item \code{MM} Full month name
#' \item \code{dd} Day of month with leading zero
#' \item \code{d} Day of month without leading zero
#' \item \code{D} Abbreviated weekday name
#' \item \code{DD} Full weekday name
#' }
#'
#' @inheritParams textInput
#' @param value The starting date. Either a Date object, or a string in
#' \code{yyyy-mm-dd} format. If NULL (the default), will use the current
#' date in the client's time zone.
#' @param min The minimum allowed date. Either a Date object, or a string in
#' \code{yyyy-mm-dd} format.
#' @param max The maximum allowed date. Either a Date object, or a string in
#' \code{yyyy-mm-dd} format.
#' @param format The format of the date to display in the browser. Defaults to
#' \code{"yyyy-mm-dd"}.
#' @param startview The date range shown when the input object is first
#' clicked. Can be "month" (the default), "year", or "decade".
#' @param weekstart Which day is the start of the week. Should be an integer
#' from 0 (Sunday) to 6 (Saturday).
#' @param language The language used for month and day names. Default is "en".
#' Other valid values include "bg", "ca", "cs", "da", "de", "el", "es", "fi",
#' "fr", "he", "hr", "hu", "id", "is", "it", "ja", "kr", "lt", "lv", "ms",
#' "nb", "nl", "pl", "pt", "pt-BR", "ro", "rs", "rs-latin", "ru", "sk", "sl",
#' "sv", "sw", "th", "tr", "uk", "zh-CN", and "zh-TW".
#'
#' @family input elements
#' @seealso \code{\link{dateRangeInput}}, \code{\link{updateDateInput}}
#'
#' @examples
#' dateInput("date", "Date:", value = "2012-02-29")
#'
#' # Default value is the date in client's time zone
#' dateInput("date", "Date:")
#'
#' # value is always yyyy-mm-dd, even if the display format is different
#' dateInput("date", "Date:", value = "2012-02-29", format = "mm/dd/yy")
#'
#' # Pass in a Date object
#' dateInput("date", "Date:", value = Sys.Date()-10)
#'
#' # Use different language and different first day of week
#' dateInput("date", "Date:",
#' language = "de",
#' weekstart = 1)
#'
#' # Start with decade view instead of default month view
#' dateInput("date", "Date:",
#' startview = "decade")
#'
#' @export
dateInput <- function(inputId, label, value = NULL, min = NULL, max = NULL,
format = "yyyy-mm-dd", startview = "month", weekstart = 0, language = "en",
width = NULL) {
# If value is a date object, convert it to a string with yyyy-mm-dd format
# Same for min and max
if (inherits(value, "Date")) value <- format(value, "%Y-%m-%d")
if (inherits(min, "Date")) min <- format(min, "%Y-%m-%d")
if (inherits(max, "Date")) max <- format(max, "%Y-%m-%d")
attachDependencies(
tags$div(id = inputId,
class = "shiny-date-input form-group shiny-input-container",
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
controlLabel(inputId, label),
tags$input(type = "text",
# datepicker class necessary for dropdown to display correctly
class = "form-control datepicker",
`data-date-language` = language,
`data-date-weekstart` = weekstart,
`data-date-format` = format,
`data-date-start-view` = startview,
`data-min-date` = min,
`data-max-date` = max,
`data-initial-date` = value
)
),
datePickerDependency
)
}
datePickerDependency <- htmlDependency(
"bootstrap-datepicker", "1.0.2", c(href = "shared/datepicker"),
script = "js/bootstrap-datepicker.min.js",
stylesheet = "css/datepicker.css")

113
R/input-daterange.R Normal file
View File

@@ -0,0 +1,113 @@
#' Create date range input
#'
#' Creates a pair of text inputs which, when clicked on, bring up calendars that
#' the user can click on to select dates.
#'
#' The date \code{format} string specifies how the date will be displayed in
#' the browser. It allows the following values:
#'
#' \itemize{
#' \item \code{yy} Year without century (12)
#' \item \code{yyyy} Year with century (2012)
#' \item \code{mm} Month number, with leading zero (01-12)
#' \item \code{m} Month number, without leading zero (01-12)
#' \item \code{M} Abbreviated month name
#' \item \code{MM} Full month name
#' \item \code{dd} Day of month with leading zero
#' \item \code{d} Day of month without leading zero
#' \item \code{D} Abbreviated weekday name
#' \item \code{DD} Full weekday name
#' }
#'
#' @inheritParams dateInput
#' @param start The initial start date. Either a Date object, or a string in
#' \code{yyyy-mm-dd} format. If NULL (the default), will use the current
#' date in the client's time zone.
#' @param end The initial end date. Either a Date object, or a string in
#' \code{yyyy-mm-dd} format. If NULL (the default), will use the current
#' date in the client's time zone.
#' @param separator String to display between the start and end input boxes.
#'
#' @family input elements
#' @seealso \code{\link{dateInput}}, \code{\link{updateDateRangeInput}}
#'
#' @examples
#' dateRangeInput("daterange", "Date range:",
#' start = "2001-01-01",
#' end = "2010-12-31")
#'
#' # Default start and end is the current date in the client's time zone
#' dateRangeInput("daterange", "Date range:")
#'
#' # start and end are always specified in yyyy-mm-dd, even if the display
#' # format is different
#' dateRangeInput("daterange", "Date range:",
#' start = "2001-01-01",
#' end = "2010-12-31",
#' min = "2001-01-01",
#' max = "2012-12-21",
#' format = "mm/dd/yy",
#' separator = " - ")
#'
#' # Pass in Date objects
#' dateRangeInput("daterange", "Date range:",
#' start = Sys.Date()-10,
#' end = Sys.Date()+10)
#'
#' # Use different language and different first day of week
#' dateRangeInput("daterange", "Date range:",
#' language = "de",
#' weekstart = 1)
#'
#' # Start with decade view instead of default month view
#' dateRangeInput("daterange", "Date range:",
#' startview = "decade")
#'
#' @export
dateRangeInput <- function(inputId, label, start = NULL, end = NULL,
min = NULL, max = NULL, format = "yyyy-mm-dd", startview = "month",
weekstart = 0, language = "en", separator = " to ", width = NULL) {
# If start and end are date objects, convert to a string with yyyy-mm-dd format
# Same for min and max
if (inherits(start, "Date")) start <- format(start, "%Y-%m-%d")
if (inherits(end, "Date")) end <- format(end, "%Y-%m-%d")
if (inherits(min, "Date")) min <- format(min, "%Y-%m-%d")
if (inherits(max, "Date")) max <- format(max, "%Y-%m-%d")
attachDependencies(
div(id = inputId,
class = "shiny-date-range-input form-group shiny-input-container",
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
controlLabel(inputId, label),
# input-daterange class is needed for dropdown behavior
div(class = "input-daterange input-group",
tags$input(
class = "input-sm form-control",
type = "text",
`data-date-language` = language,
`data-date-weekstart` = weekstart,
`data-date-format` = format,
`data-date-start-view` = startview,
`data-min-date` = min,
`data-max-date` = max,
`data-initial-date` = start
),
span(class = "input-group-addon", separator),
tags$input(
class = "input-sm form-control",
type = "text",
`data-date-language` = language,
`data-date-weekstart` = weekstart,
`data-date-format` = format,
`data-date-start-view` = startview,
`data-min-date` = min,
`data-max-date` = max,
`data-initial-date` = end
)
)
),
datePickerDependency
)
}

51
R/input-file.R Normal file
View File

@@ -0,0 +1,51 @@
#' File Upload Control
#'
#' 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:
#' \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
#' (see
#' \code{datapath} column).}
#' \item{\code{size}}{The size of the uploaded data, in
#' bytes.}
#' \item{\code{type}}{The MIME type reported by the browser (for example,
#' \code{text/plain}), or empty string if the browser didn't know.}
#' \item{\code{datapath}}{The path to a temp file that contains the data that was
#' uploaded. This file may be deleted if the user performs another upload
#' operation.}
#' }
#'
#' @family input elements
#'
#' @inheritParams textInput
#' @param multiple Whether the user should be allowed to select and upload
#' multiple files at once. \bold{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.
#'
#' @export
fileInput <- function(inputId, label, multiple = FALSE, accept = NULL,
width = NULL) {
inputTag <- tags$input(id = inputId, name = inputId, type = "file")
if (multiple)
inputTag$attribs$multiple <- "multiple"
if (length(accept) > 0)
inputTag$attribs$accept <- paste(accept, collapse=',')
div(class = "form-group shiny-input-container",
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
label %AND% tags$label(label),
inputTag,
tags$div(
id=paste(inputId, "_progress", sep=""),
class="progress progress-striped active shiny-file-input-progress",
tags$div(class="progress-bar")
)
)
}

37
R/input-numeric.R Normal file
View File

@@ -0,0 +1,37 @@
#' Create a numeric input control
#'
#' Create an input control for entry of numeric values
#'
#' @inheritParams textInput
#' @param min Minimum allowed value
#' @param max Maximum allowed value
#' @param step Interval to use when stepping between min and max
#' @return A numeric input control that can be added to a UI definition.
#'
#' @family input elements
#' @seealso \code{\link{updateNumericInput}}
#'
#' @examples
#' numericInput("obs", "Observations:", 10,
#' min = 1, max = 100)
#' @export
numericInput <- function(inputId, label, value, min = NA, max = NA, step = NA,
width = NULL) {
# build input tag
inputTag <- tags$input(id = inputId, type = "number", class="form-control",
value = formatNoSci(value))
if (!is.na(min))
inputTag$attribs$min = min
if (!is.na(max))
inputTag$attribs$max = max
if (!is.na(step))
inputTag$attribs$step = step
div(class = "form-group shiny-input-container",
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
label %AND% tags$label(label, `for` = inputId),
inputTag
)
}

20
R/input-password.R Normal file
View File

@@ -0,0 +1,20 @@
#' Create a password input control
#'
#' Create an password control for entry of passwords.
#'
#' @inheritParams textInput
#' @return A text input control that can be added to a UI definition.
#'
#' @family input elements
#' @seealso \code{\link{updateTextInput}}
#'
#' @examples
#' passwordInput("password", "Password:")
#' @export
passwordInput <- function(inputId, label, value = "", width = NULL) {
div(class = "form-group shiny-input-container",
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
label %AND% tags$label(label, `for` = inputId),
tags$input(id = inputId, type="password", class="form-control", value=value)
)
}

54
R/input-radiobuttons.R Normal file
View File

@@ -0,0 +1,54 @@
#' Create radio buttons
#'
#' Create a set of radio buttons used to select an item from a list.
#'
#' If you need to represent a "None selected" state, it's possible to default
#' the radio buttons to have no options selected by using
#' \code{selected = character(0)}. However, this is not recommended, as it gives
#' the user no way to return to that state once they've made a selection.
#' Instead, consider having the first of your choices be \code{c("None selected"
#' = "")}.
#'
#' @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)
#' @param selected The initially selected value (if not specified then
#' defaults to the first value)
#' @param inline If \code{TRUE}, render the choices inline (i.e. horizontally)
#' @return A set of radio buttons that can be added to a UI definition.
#'
#' @family input elements
#' @seealso \code{\link{updateRadioButtons}}
#'
#' @examples
#' radioButtons("dist", "Distribution type:",
#' c("Normal" = "norm",
#' "Uniform" = "unif",
#' "Log-normal" = "lnorm",
#' "Exponential" = "exp"))
#' @export
radioButtons <- function(inputId, label, choices, selected = NULL,
inline = FALSE, width = NULL) {
# resolve names
choices <- choicesWithNames(choices)
# default value if it's not specified
selected <- if (is.null(selected)) choices[[1]] else {
validateSelected(selected, choices, inputId)
}
if (length(selected) > 1) stop("The 'selected' argument must be of length 1")
options <- generateOptions(inputId, choices, selected, inline, type = 'radio')
divClass <- "form-group shiny-input-radiogroup shiny-input-container"
if (inline)
divClass <- paste(divClass, "shiny-input-container-inline")
tags$div(id = inputId,
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
class = divClass,
controlLabel(inputId, label),
options
)
}

174
R/input-select.R Normal file
View File

@@ -0,0 +1,174 @@
#' Create a select list input control
#'
#' Create a select list that can be used to choose a single or multiple items
#' from a list of values.
#'
#' By default, \code{selectInput()} and \code{selectizeInput()} use the
#' JavaScript library \pkg{selectize.js}
#' (\url{https://github.com/brianreavis/selectize.js}) to instead of the basic
#' select input element. To use the standard HTML select input element, use
#' \code{selectInput()} with \code{selectize=FALSE}.
#'
#' In selectize mode, if the first element in \code{choices} has a value of
#' \code{""}, its name will be treated as a placeholder prompt. For example:
#' \code{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.
#' @param selected The initially selected value (or multiple values if
#' \code{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 \code{selectize=TRUE}.
#' Normally, when \code{multiple=FALSE}, a select input will be a drop-down
#' list, but when \code{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
#' @seealso \code{\link{updateSelectInput}}
#'
#' @examples
#' selectInput("variable", "Variable:",
#' c("Cylinders" = "cyl",
#' "Transmission" = "am",
#' "Gears" = "gear"))
#' @export
selectInput <- function(inputId, label, choices, selected = NULL,
multiple = FALSE, selectize = TRUE, width = NULL,
size = NULL) {
# resolve names
choices <- choicesWithNames(choices)
# default value if it's not specified
if (is.null(selected)) {
if (!multiple) selected <- firstChoice(choices)
} else selected <- validateSelected(selected, choices, inputId)
if (!is.null(size) && selectize) {
stop("'size' argument is incompatible with 'selectize=TRUE'.")
}
# create select tag and add options
selectTag <- tags$select(
id = inputId,
class = if (!selectize) "form-control",
size = size,
selectOptions(choices, selected)
)
if (multiple)
selectTag$attribs$multiple <- "multiple"
# return label and select tag
res <- div(
class = "form-group shiny-input-container",
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
controlLabel(inputId, label),
div(selectTag)
)
if (!selectize) return(res)
selectizeIt(inputId, res, NULL, nonempty = !multiple && !("" %in% choices))
}
firstChoice <- function(choices) {
if (length(choices) == 0L) return()
choice <- choices[[1]]
if (is.list(choice)) firstChoice(choice) else choice
}
# Create tags for each of the options; use <optgroup> if necessary.
# This returns a HTML string instead of tags, because of the 'selected'
# attribute.
selectOptions <- function(choices, selected = NULL) {
html <- mapply(choices, names(choices), FUN = function(choice, label) {
if (is.list(choice)) {
# If sub-list, create an optgroup and recurse into the sublist
sprintf(
'<optgroup label="%s">\n%s\n</optgroup>',
htmlEscape(label, TRUE),
selectOptions(choice, selected)
)
} else {
# If single item, just return option string
sprintf(
'<option value="%s"%s>%s</option>',
htmlEscape(choice, TRUE),
if (choice %in% selected) ' selected' else '',
htmlEscape(label)
)
}
})
HTML(paste(html, collapse = '\n'))
}
# need <optgroup> when choices contains sub-lists
needOptgroup <- function(choices) {
any(vapply(choices, is.list, logical(1)))
}
#' @rdname selectInput
#' @param ... Arguments passed to \code{selectInput()}.
#' @param options A list of options. See the documentation of \pkg{selectize.js}
#' for possible options (character option values inside \code{\link{I}()} will
#' be treated as literal JavaScript code; see \code{\link{renderDataTable}()}
#' for details).
#' @param width The width of the input, e.g. \code{'400px'}, or \code{'100\%'};
#' see \code{\link{validateCssUnit}}.
#' @note The selectize input created from \code{selectizeInput()} allows
#' deletion of the selected option even in a single select input, which will
#' return an empty string as its value. This is the default behavior of
#' \pkg{selectize.js}. However, the selectize input created from
#' \code{selectInput(..., selectize = TRUE)} will ignore the empty string
#' value when it is a single choice input and the empty string is not in the
#' \code{choices} argument. This is to keep compatibility with
#' \code{selectInput(..., selectize = FALSE)}.
#' @export
selectizeInput <- function(inputId, ..., options = NULL, width = NULL) {
selectizeIt(
inputId,
selectInput(inputId, ..., selectize = FALSE, width = width),
options
)
}
# given a select input and its id, selectize it
selectizeIt <- function(inputId, select, options, nonempty = FALSE) {
res <- checkAsIs(options)
selectizeDep <- htmlDependency(
"selectize", "0.11.2", c(href = "shared/selectize"),
stylesheet = "css/selectize.bootstrap3.css",
head = format(tagList(
HTML('<!--[if lt IE 9]>'),
tags$script(src = 'shared/selectize/js/es5-shim.min.js'),
HTML('<![endif]-->'),
tags$script(src = 'shared/selectize/js/selectize.min.js')
))
)
if ('drag_drop' %in% options$plugins) {
selectizeDep <- list(selectizeDep, htmlDependency(
'jqueryui', '1.11.4', c(href = 'shared/jqueryui'),
script = 'jquery-ui.min.js'
))
}
# Insert script on same level as <select> tag
select$children[[2]] <- tagAppendChild(
select$children[[2]],
tags$script(
type = 'application/json',
`data-for` = inputId, `data-nonempty` = if (nonempty) '',
`data-eval` = if (length(res$eval)) HTML(toJSON(res$eval)),
if (length(res$options)) HTML(toJSON(res$options)) else '{}'
)
)
attachDependencies(select, selectizeDep)
}

234
R/input-slider.R Normal file
View File

@@ -0,0 +1,234 @@
#' Slider Input Widget
#'
#' Constructs a slider widget to select a numeric value from a range.
#'
#' @inheritParams textInput
#' @param min The minimum value (inclusive) that can be selected.
#' @param max The maximum value (inclusive) that can be selected.
#' @param value The initial value of the slider. A numeric vector of length one
#' will create a regular slider; a numeric vector of length two will create a
#' double-ended range slider. A warning will be issued if the value doesn't
#' fit between \code{min} and \code{max}.
#' @param step Specifies the interval between each selectable value on the
#' slider (if \code{NULL}, a heuristic is used to determine the step size). If
#' the values are dates, \code{step} is in days; if the values are times
#' (POSIXt), \code{step} is in seconds.
#' @param round \code{TRUE} to round all values to the nearest integer;
#' \code{FALSE} if no rounding is desired; or an integer to round to that
#' number of digits (for example, 1 will round to the nearest 10, and -2 will
#' round to the nearest .01). Any rounding will be applied after snapping to
#' the nearest step.
#' @param format Deprecated.
#' @param locale Deprecated.
#' @param ticks \code{FALSE} to hide tick marks, \code{TRUE} to show them
#' according to some simple heuristics.
#' @param animate \code{TRUE} to show simple animation controls with default
#' settings; \code{FALSE} not to; or a custom settings list, such as those
#' created using \code{\link{animationOptions}}.
#' @param sep Separator between thousands places in numbers.
#' @param pre A prefix string to put in front of the value.
#' @param post A suffix string to put after the value.
#' @param dragRange This option is used only if it is a range slider (with two
#' values). If \code{TRUE} (the default), the range can be dragged. In other
#' words, the min and max can be dragged together. If \code{FALSE}, the range
#' cannot be dragged.
#' @param timeFormat Only used if the values are Date or POSIXt objects. A time
#' format string, to be passed to the Javascript strftime library. See
#' \url{https://github.com/samsonjs/strftime} for more details. The allowed
#' format specifications are very similar, but not identical, to those for R's
#' \code{\link{strftime}} function. For Dates, the default is \code{"\%F"}
#' (like \code{"2015-07-01"}), and for POSIXt, the default is \code{"\%F \%T"}
#' (like \code{"2015-07-01 15:32:10"}).
#' @param timezone Only used if the values are POSIXt objects. A string
#' specifying the time zone offset for the displayed times, in the format
#' \code{"+HHMM"} or \code{"-HHMM"}. If \code{NULL} (the default), times will
#' be displayed in the browser's time zone. The value \code{"+0000"} will
#' result in UTC time.
#' @inheritParams selectizeInput
#' @family input elements
#' @seealso \code{\link{updateSliderInput}}
#'
#' @export
sliderInput <- function(inputId, label, min, max, value, step = NULL,
round = FALSE, format = NULL, locale = NULL,
ticks = TRUE, animate = FALSE, width = NULL, sep = ",",
pre = NULL, post = NULL, timeFormat = NULL,
timezone = NULL, dragRange = TRUE)
{
if (!missing(format)) {
shinyDeprecated(msg = "The `format` argument to sliderInput is deprecated. Use `sep`, `pre`, and `post` instead.",
version = "0.10.2.2")
}
if (!missing(locale)) {
shinyDeprecated(msg = "The `locale` argument to sliderInput is deprecated. Use `sep`, `pre`, and `post` instead.",
version = "0.10.2.2")
}
# If step is NULL, use heuristic to set the step size.
findStepSize <- function(min, max, step) {
if (!is.null(step)) return(step)
range <- max - min
# If short range or decimals, use continuous decimal with ~100 points
if (range < 2 || hasDecimals(min) || hasDecimals(max)) {
step <- pretty(c(min, max), n = 100)
step[2] - step[1]
} else {
1
}
}
if (inherits(min, "Date")) {
if (!inherits(max, "Date") || !inherits(value, "Date"))
stop("`min`, `max`, and `value must all be Date or non-Date objects")
dataType <- "date"
if (is.null(timeFormat))
timeFormat <- "%F"
} else if (inherits(min, "POSIXt")) {
if (!inherits(max, "POSIXt") || !inherits(value, "POSIXt"))
stop("`min`, `max`, and `value must all be POSIXt or non-POSIXt objects")
dataType <- "datetime"
if (is.null(timeFormat))
timeFormat <- "%F %T"
} else {
dataType <- "number"
}
step <- findStepSize(min, max, step)
if (dataType %in% c("date", "datetime")) {
# For Dates, this conversion uses midnight on that date in UTC
to_ms <- function(x) 1000 * as.numeric(as.POSIXct(x))
# Convert values to milliseconds since epoch (this is the value JS uses)
# Find step size in ms
step <- to_ms(max) - to_ms(max - step)
min <- to_ms(min)
max <- to_ms(max)
value <- to_ms(value)
}
range <- max - min
# Try to get a sane number of tick marks
if (ticks) {
n_steps <- range / step
# Make sure there are <= 10 steps.
# n_ticks can be a noninteger, which is good when the range is not an
# integer multiple of the step size, e.g., min=1, max=10, step=4
scale_factor <- ceiling(n_steps / 10)
n_ticks <- n_steps / scale_factor
} else {
n_ticks <- NULL
}
sliderProps <- dropNulls(list(
class = "js-range-slider",
id = inputId,
`data-type` = if (length(value) > 1) "double",
`data-min` = formatNoSci(min),
`data-max` = formatNoSci(max),
`data-from` = formatNoSci(value[1]),
`data-to` = if (length(value) > 1) formatNoSci(value[2]),
`data-step` = formatNoSci(step),
`data-grid` = ticks,
`data-grid-num` = n_ticks,
`data-grid-snap` = FALSE,
`data-prettify-separator` = sep,
`data-prefix` = pre,
`data-postfix` = post,
`data-keyboard` = TRUE,
`data-keyboard-step` = step / (max - min) * 100,
`data-drag-interval` = dragRange,
# The following are ignored by the ion.rangeSlider, but are used by Shiny.
`data-data-type` = dataType,
`data-time-format` = timeFormat,
`data-timezone` = timezone
))
# Replace any TRUE and FALSE with "true" and "false"
sliderProps <- lapply(sliderProps, function(x) {
if (identical(x, TRUE)) "true"
else if (identical(x, FALSE)) "false"
else x
})
sliderTag <- div(class = "form-group shiny-input-container",
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
if (!is.null(label)) controlLabel(inputId, label),
do.call(tags$input, sliderProps)
)
# Add animation buttons
if (identical(animate, TRUE))
animate <- animationOptions()
if (!is.null(animate) && !identical(animate, FALSE)) {
if (is.null(animate$playButton))
animate$playButton <- icon('play', lib = 'glyphicon')
if (is.null(animate$pauseButton))
animate$pauseButton <- icon('pause', lib = 'glyphicon')
sliderTag <- tagAppendChild(
sliderTag,
tags$div(class='slider-animate-container',
tags$a(href='#',
class='slider-animate-button',
'data-target-id'=inputId,
'data-interval'=animate$interval,
'data-loop'=animate$loop,
span(class = 'play', animate$playButton),
span(class = 'pause', animate$pauseButton)
)
)
)
}
dep <- list(
htmlDependency("ionrangeslider", "2.0.12", c(href="shared/ionrangeslider"),
script = "js/ion.rangeSlider.min.js",
# ion.rangeSlider also needs normalize.css, which is already included in
# Bootstrap.
stylesheet = c("css/ion.rangeSlider.css",
"css/ion.rangeSlider.skinShiny.css")
),
htmlDependency("strftime", "0.9.2", c(href="shared/strftime"),
script = "strftime-min.js"
)
)
attachDependencies(sliderTag, dep)
}
hasDecimals <- function(value) {
truncatedValue <- round(value)
return (!identical(value, truncatedValue))
}
#' @rdname sliderInput
#'
#' @param interval The interval, in milliseconds, between each animation step.
#' @param loop \code{TRUE} to automatically restart the animation when it
#' reaches the end.
#' @param playButton Specifies the appearance of the play button. Valid values
#' are a one-element character vector (for a simple text label), an HTML tag
#' or list of tags (using \code{\link{tag}} and friends), or raw HTML (using
#' \code{\link{HTML}}).
#' @param pauseButton Similar to \code{playButton}, but for the pause button.
#'
#' @export
animationOptions <- function(interval=1000,
loop=FALSE,
playButton=NULL,
pauseButton=NULL) {
list(interval=interval,
loop=loop,
playButton=playButton,
pauseButton=pauseButton)
}

28
R/input-submit.R Normal file
View File

@@ -0,0 +1,28 @@
#' Create a submit button
#'
#' Create a submit button for an input form. Forms that include a submit
#' button do not automatically update their outputs when inputs change,
#' rather they wait until the user explicitly clicks the submit button.
#'
#' @param text Button caption
#' @param icon Optional \code{\link{icon}} to appear on the button
#' @param width The width of the button, e.g. \code{'400px'}, or \code{'100\%'};
#' see \code{\link{validateCssUnit}}.
#' @return A submit button that can be added to a UI definition.
#'
#' @family input elements
#'
#' @examples
#' submitButton("Update View")
#' submitButton("Update View", icon("refresh"))
#' @export
submitButton <- function(text = "Apply Changes", icon = NULL, width = NULL) {
div(
tags$button(
type="submit",
class="btn btn-primary",
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
list(icon, text)
)
)
}

30
R/input-text.R Normal file
View File

@@ -0,0 +1,30 @@
#' Create a text input control
#'
#' Create an input control for entry of unstructured text values
#'
#' @param inputId The \code{input} slot that will be used to access the value.
#' @param label Display label for the control, or \code{NULL} for no label.
#' @param value Initial value.
#' @param width The width of the input, e.g. \code{'400px'}, or \code{'100\%'};
#' see \code{\link{validateCssUnit}}.
#' @param placeholder A character string giving the user a hint as to what can
#' be entered into the control. Internet Explorer 8 and 9 do not support this
#' option.
#' @return A text input control that can be added to a UI definition.
#'
#' @family input elements
#' @seealso \code{\link{updateTextInput}}
#'
#' @examples
#' textInput("caption", "Caption:", "Data Summary")
#' @export
textInput <- function(inputId, label, value = "", width = NULL,
placeholder = NULL) {
div(class = "form-group shiny-input-container",
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
label %AND% tags$label(label, `for` = inputId),
tags$input(id = inputId, type="text", class="form-control", value=value,
placeholder = placeholder)
)
}

105
R/input-utils.R Normal file
View File

@@ -0,0 +1,105 @@
controlLabel <- function(controlName, label) {
label %AND% tags$label(class = "control-label", `for` = controlName, label)
}
# Before shiny 0.9, `selected` refers to names/labels of `choices`; now it
# refers to values. Below is a function for backward compatibility.
validateSelected <- function(selected, choices, inputId) {
# drop names, otherwise toJSON() keeps them too
selected <- unname(selected)
# if you are using optgroups, you're using shiny > 0.10.0, and you should
# already know that `selected` must be a value instead of a label
if (needOptgroup(choices)) return(selected)
if (is.list(choices)) choices <- unlist(choices)
nms <- names(choices)
# labels and values are identical, no need to validate
if (identical(nms, unname(choices))) return(selected)
# when selected labels instead of values
i <- (selected %in% nms) & !(selected %in% choices)
if (any(i)) {
warnFun <- if (all(i)) {
# replace names with values
selected <- unname(choices[selected])
warning
} else stop # stop when it is ambiguous (some labels == values)
warnFun("'selected' must be the values instead of names of 'choices' ",
"for the input '", inputId, "'")
}
selected
}
# generate options for radio buttons and checkbox groups (type = 'checkbox' or
# 'radio')
generateOptions <- function(inputId, choices, selected, inline, type = 'checkbox') {
# generate a list of <input type=? [checked] />
options <- mapply(
choices, names(choices),
FUN = function(value, name) {
inputTag <- tags$input(
type = type, name = inputId, value = value
)
if (value %in% selected)
inputTag$attribs$checked <- "checked"
# If inline, there's no wrapper div, and the label needs a class like
# checkbox-inline.
if (inline) {
tags$label(class = paste0(type, "-inline"), inputTag, tags$span(name))
} else {
tags$div(class = type,
tags$label(inputTag, tags$span(name))
)
}
},
SIMPLIFY = FALSE, USE.NAMES = FALSE
)
div(class = "shiny-options-group", options)
}
# Takes a vector or list, and adds names (same as the value) to any entries
# without names.
choicesWithNames <- function(choices) {
# Take a vector or list, and convert to list. Also, if any children are
# vectors with length > 1, convert those to list. If the list is unnamed,
# convert it to a named list with blank names.
listify <- function(obj) {
# If a list/vector is unnamed, give it blank names
makeNamed <- function(x) {
if (is.null(names(x))) names(x) <- character(length(x))
x
}
res <- lapply(obj, function(val) {
if (is.list(val))
listify(val)
else if (length(val) == 1 && is.null(names(val)))
val
else
makeNamed(as.list(val))
})
makeNamed(res)
}
choices <- listify(choices)
if (length(choices) == 0) return(choices)
# Recurse into any subgroups
choices <- mapply(choices, names(choices), FUN = function(choice, name) {
if (!is.list(choice)) return(choice)
if (name == "") stop('All sub-lists in "choices" must be named.')
choicesWithNames(choice)
}, SIMPLIFY = FALSE)
# default missing names to choice values
missing <- names(choices) == ""
names(choices)[missing] <- as.character(choices)[missing]
choices
}

104
R/jqueryui.R Normal file
View File

@@ -0,0 +1,104 @@
#' Panel with absolute positioning
#'
#' Creates a panel whose contents are absolutely positioned.
#'
#' The \code{absolutePanel} function creates a \code{<div>} tag whose CSS
#' position is set to \code{absolute} (or fixed if \code{fixed = TRUE}). The way
#' absolute positioning works in HTML is that absolute coordinates are specified
#' relative to its nearest parent element whose position is not set to
#' \code{static} (which is the default), and if no such parent is found, then
#' relative to the page borders. If you're not sure what that means, just keep
#' in mind that you may get strange results if you use \code{absolutePanel} from
#' inside of certain types of panels.
#'
#' The \code{fixedPanel} function is the same as \code{absolutePanel} with
#' \code{fixed = TRUE}.
#'
#' The position (\code{top}, \code{left}, \code{right}, \code{bottom}) and size
#' (\code{width}, \code{height}) parameters are all optional, but you should
#' specify exactly two of \code{top}, \code{bottom}, and \code{height} and
#' exactly two of \code{left}, \code{right}, and \code{width} for predictable
#' results.
#'
#' Like most other distance parameters in Shiny, the position and size
#' parameters take a number (interpreted as pixels) or a valid CSS size string,
#' such as \code{"100px"} (100 pixels) or \code{"25\%"}.
#'
#' For arcane HTML reasons, to have the panel fill the page or parent you should
#' specify \code{0} for \code{top}, \code{left}, \code{right}, and \code{bottom}
#' rather than the more obvious \code{width = "100\%"} and \code{height =
#' "100\%"}.
#'
#' @param ... Attributes (named arguments) or children (unnamed arguments) that
#' should be included in the panel.
#'
#' @param top Distance between the top of the panel, and the top of the page or
#' parent container.
#' @param left Distance between the left side of the panel, and the left of the
#' page or parent container.
#' @param right Distance between the right side of the panel, and the right of
#' the page or parent container.
#' @param bottom Distance between the bottom of the panel, and the bottom of the
#' page or parent container.
#' @param width Width of the panel.
#' @param height Height of the panel.
#' @param draggable If \code{TRUE}, allows the user to move the panel by
#' clicking and dragging.
#' @param fixed Positions the panel relative to the browser window and prevents
#' it from being scrolled with the rest of the page.
#' @param cursor The type of cursor that should appear when the user mouses over
#' the panel. Use \code{"move"} for a north-east-south-west icon,
#' \code{"default"} for the usual cursor arrow, or \code{"inherit"} for the
#' usual cursor behavior (including changing to an I-beam when the cursor is
#' over text). The default is \code{"auto"}, which is equivalent to
#' \code{ifelse(draggable, "move", "inherit")}.
#' @return An HTML element or list of elements.
#'
#' @export
absolutePanel <- function(...,
top = NULL, left = NULL, right = NULL, bottom = NULL,
width = NULL, height = NULL,
draggable = FALSE, fixed = FALSE,
cursor = c('auto', 'move', 'default', 'inherit')) {
cssProps <- list(
top = top,
left = left,
right = right,
bottom = bottom,
width = width,
height = height
)
cssProps <- cssProps[!sapply(cssProps, is.null)]
cssProps <- sapply(cssProps, validateCssUnit)
cssProps[['position']] <- ifelse(fixed, 'fixed', 'absolute')
cssProps[['cursor']] <- match.arg(cursor)
if (identical(cssProps[['cursor']], 'auto'))
cssProps[['cursor']] <- ifelse(draggable, 'move', 'inherit')
style <- paste(paste(names(cssProps), cssProps, sep = ':', collapse = ';'), ';', sep='')
divTag <- tags$div(style=style, ...)
if (isTRUE(draggable)) {
divTag <- tagAppendAttributes(divTag, class='draggable')
return(tagList(
# IMPORTANT NOTE: If you update jqueryui, make sure you DON'T include the datepicker,
# as it collides with our bootstrap datepicker!
singleton(tags$head(tags$script(src='shared/jqueryui/jquery-ui.min.js'))),
divTag,
tags$script('$(".draggable").draggable();')
))
} else {
return(divTag)
}
}
#' @rdname absolutePanel
#' @export
fixedPanel <- function(...,
top = NULL, left = NULL, right = NULL, bottom = NULL,
width = NULL, height = NULL,
draggable = FALSE,
cursor = c('auto', 'move', 'default', 'inherit')) {
absolutePanel(..., top=top, left=left, right=right, bottom=bottom,
width=width, height=height, draggable=draggable, cursor=match.arg(cursor),
fixed=TRUE)
}

64
R/map.R
View File

@@ -9,62 +9,68 @@
# Remove of unknown key does nothing
# Setting a key twice always results in last-one-wins
# /TESTS
Map <- setRefClass(
Map <- R6Class(
'Map',
fields = list(
.env = 'environment'
),
methods = list(
portable = FALSE,
public = list(
initialize = function() {
.env <<- new.env(parent=emptyenv())
private$env <- new.env(parent=emptyenv())
},
get = function(key) {
if (.self$containsKey(key))
return(base::get(key, pos=.env, inherits=FALSE))
else
return(NULL)
env[[key]]
},
set = function(key, value) {
assign(key, value, pos=.env, inherits=FALSE)
return(value)
env[[key]] <- value
value
},
mget = function(keys) {
base::mget(keys, env)
},
mset = function(...) {
args <- list(...)
for (key in names(args))
set(key, args[[key]])
return()
if (length(args) == 0)
return()
arg_names <- names(args)
if (is.null(arg_names) || any(!nzchar(arg_names)))
stop("All elements must be named")
list2env(args, envir = env)
},
remove = function(key) {
if (.self$containsKey(key)) {
result <- .self$get(key)
rm(list = key, pos=.env, inherits=FALSE)
return(result)
}
return(NULL)
if (!self$containsKey(key))
return(NULL)
result <- env[[key]]
rm(list=key, envir=env, inherits=FALSE)
result
},
containsKey = function(key) {
exists(key, where=.env, inherits=FALSE)
exists(key, envir=env, inherits=FALSE)
},
keys = function() {
ls(envir=.env, all.names=TRUE)
# Sadly, this is much faster than ls(), because it doesn't sort the keys.
names(as.list(env, all.names=TRUE))
},
values = function() {
mget(.self$keys(), envir=.env, inherits=FALSE)
as.list(env, all.names=TRUE)
},
clear = function() {
.env <<- new.env(parent=emptyenv())
private$env <- new.env(parent=emptyenv())
invisible(NULL)
},
size = function() {
length(.env)
length(env)
}
),
private = list(
env = 'environment'
)
)
as.list.Map <- function(map) {
sapply(map$keys(),
map$get,
simplify=FALSE)
map$values()
}
length.Map <- function(map) {
map$size()

43
R/middleware-shiny.R Normal file
View File

@@ -0,0 +1,43 @@
#' @include globals.R
NULL
reactLogHandler <- function(req) {
if (!identical(req$PATH_INFO, '/reactlog'))
return(NULL)
if (!isTRUE(getOption('shiny.reactlog'))) {
return(NULL)
}
sessionToken <- parseQueryString(req$QUERY_STRING)$s
return(httpResponse(
status=200,
content=list(file=renderReactLog(sessionToken), owned=TRUE)
))
}
sessionHandler <- function(req) {
path <- req$PATH_INFO
if (is.null(path))
return(NULL)
matches <- regmatches(path, regexec('^(/session/([0-9a-f]+))(/.*)$', path))
if (length(matches[[1]]) == 0)
return(NULL)
session <- matches[[1]][3]
subpath <- matches[[1]][4]
shinysession <- appsByToken$get(session)
if (is.null(shinysession))
return(NULL)
subreq <- as.environment(as.list(req, all.names=TRUE))
subreq$PATH_INFO <- subpath
subreq$SCRIPT_NAME <- paste(subreq$SCRIPT_NAME, matches[[1]][2], sep='')
withReactiveDomain(shinysession, {
shinysession$handleRequest(subreq)
})
}

381
R/middleware.R Normal file
View File

@@ -0,0 +1,381 @@
# This file contains a general toolkit for routing and combining bits of
# HTTP-handling logic. It is similar in spirit to Rook (and Rack, and WSGI, and
# Connect, and...) but adds cascading and routing.
#
# This file is called "middleware" because that's the term used for these bits
# of logic in these other frameworks. However, our code uses the word "handler"
# so we'll stick to that for the rest of this document; just know that they're
# basically the same concept.
#
# ## Intro to handlers
#
# A **handler** (or sometimes, **httpHandler**) is a function that takes a
# `req` parameter--a request object as described in the Rook specification--and
# returns `NULL`, or an `httpResponse`.
#
## ------------------------------------------------------------------------
httpResponse <- function(status = 200,
content_type = "text/html; charset=UTF-8",
content = "",
headers = list()) {
# Make sure it's a list, not a vector
headers <- as.list(headers)
if (is.null(headers$`X-UA-Compatible`))
headers$`X-UA-Compatible` <- "IE=edge,chrome=1"
resp <- list(status = status, content_type = content_type, content = content,
headers = headers)
class(resp) <- 'httpResponse'
return(resp)
}
#
# You can think of a web application as being simply an aggregation of these
# functions, each of which performs one kind of duty. Each handler in turn gets
# a look at the request and can decide whether it knows how to handle it. If
# so, it returns an `httpResponse` and processing terminates; if not, it
# returns `NULL` and the next handler gets to execute. If the final handler
# returns `NULL`, a 404 response should be returned.
#
# We have a similar construct for websockets: **websocket handlers** or
# **wsHandlers**. These take a single `ws` argument which is the websocket
# connection that was just opened, and they can either return `TRUE` if they
# are handling the connection, and `NULL` to pass responsibility on to the next
# wsHandler.
#
# ### Combining handlers
#
# Since it's so common for httpHandlers to be invoked in this "cascading"
# fashion, we'll introduce a function that takes zero or more handlers and
# returns a single handler. And while we're at it, making a directory of static
# content available is such a common thing to do, we'll allow strings
# representing paths to be used instead of handlers; any such strings we
# encounter will be converted into `staticHandler` objects.
#
## ------------------------------------------------------------------------
joinHandlers <- function(handlers) {
# Zero handlers; return a null handler
if (length(handlers) == 0)
return(function(req) NULL)
# Just one handler (function)? Return it.
if (is.function(handlers))
return(handlers)
handlers <- lapply(handlers, function(h) {
if (is.character(h))
return(staticHandler(h))
else
return(h)
})
# Filter out NULL
handlers <- handlers[!sapply(handlers, is.null)]
if (length(handlers) == 0)
return(function(req) NULL)
if (length(handlers) == 1)
return(handlers[[1]])
function(req) {
for (handler in handlers) {
response <- handler(req)
if (!is.null(response))
return(response)
}
return(NULL)
}
}
#
# Note that we don't have an equivalent of `joinHandlers` for wsHandlers. It's
# easy to imagine it, we just haven't needed one.
#
# ### Handler routing
#
# Handlers do not have a built-in notion of routing. Conceptually, given a list
# of handlers, all the handlers are peers and they all get to see every request
# (well, up until the point that a handler returns a response).
#
# You could implement routing in each handler by checking the request's
# `PATH_INFO` field, but since it's such a common need, let's make it simple by
# introducing a `routeHandler` function. This is a handler
# [decorator](http://en.wikipedia.org/wiki/Decorator_pattern) and it's
# responsible for 1) filtering out requests that don't match the given route,
# and 2) temporarily modifying the request object to take the matched part of
# the route off of the `PATH_INFO` (and add it to the end of `SCRIPT_NAME`).
# This way, the handler doesn't need to figure out about what part of its URL
# path has already been matched via routing.
#
# (BTW, it's safe for `routeHandler` calls to nest.)
#
## ------------------------------------------------------------------------
routeHandler <- function(prefix, handler) {
force(prefix)
force(handler)
if (identical("", prefix))
return(handler)
if (length(prefix) != 1 || !isTRUE(grepl("^/[^\\]+$", prefix))) {
stop("Invalid URL prefix \"", prefix, "\"")
}
pathPattern <- paste("^\\Q", prefix, "\\E/", sep = "")
function(req) {
if (isTRUE(grepl(pathPattern, req$PATH_INFO))) {
origScript <- req$SCRIPT_NAME
origPath <- req$PATH_INFO
on.exit({
req$SCRIPT_NAME <- origScript
req$PATH_INFO <- origPath
}, add = TRUE)
pathInfo <- substr(req$PATH_INFO, nchar(prefix)+1, nchar(req$PATH_INFO))
req$SCRIPT_NAME <- paste(req$SCRIPT_NAME, prefix, sep = "")
req$PATH_INFO <- pathInfo
return(handler(req))
} else {
return(NULL)
}
}
}
#
# We have a version for websocket handlers as well. Pity about the copy/paste
# job.
#
## ------------------------------------------------------------------------
routeWSHandler <- function(prefix, wshandler) {
force(prefix)
force(wshandler)
if (identical("", prefix))
return(wshandler)
if (length(prefix) != 1 || !isTRUE(grepl("^/[^\\]+$", prefix))) {
stop("Invalid URL prefix \"", prefix, "\"")
}
pathPattern <- paste("^\\Q", prefix, "\\E/", sep = "")
function(ws) {
req <- ws$request
if (isTRUE(grepl(pathPattern, req$PATH_INFO))) {
origScript <- req$SCRIPT_NAME
origPath <- req$PATH_INFO
on.exit({
req$SCRIPT_NAME <- origScript
req$PATH_INFO <- origPath
}, add = TRUE)
pathInfo <- substr(req$PATH_INFO, nchar(prefix)+1, nchar(req$PATH_INFO))
req$SCRIPT_NAME <- paste(req$SCRIPT_NAME, prefix, sep = "")
req$PATH_INFO <- pathInfo
return(wshandler(ws))
} else {
return(NULL)
}
}
}
#
# ### Handler implementations
#
# Now let's actually write some handlers. Note that these functions aren't
# *themselves* handlers, you call them and they *return* a handler. Handler
# factory functions, if you will.
#
# Here's one that serves up static assets from a directory.
#
## ------------------------------------------------------------------------
staticHandler <- function(root) {
force(root)
return(function(req) {
if (!identical(req$REQUEST_METHOD, 'GET'))
return(NULL)
path <- req$PATH_INFO
if (is.null(path))
return(httpResponse(400, content="<h1>Bad Request</h1>"))
if (path == '/')
path <- '/index.html'
abs.path <- resolve(root, path)
if (is.null(abs.path))
return(NULL)
content.type <- getContentType(abs.path)
response.content <- readBin(abs.path, 'raw', n=file.info(abs.path)$size)
return(httpResponse(200, content.type, response.content))
})
}
#
# ## Handler manager
#
# The handler manager gives you a place to register handlers (of both http and
# websocket varieties) and provides an httpuv-compatible set of callbacks for
# invoking them.
#
# Create one of these, make zero or more calls to `addHandler` and
# `addWSHandler` methods (order matters--first one wins!), and then pass the
# return value of `createHttpuvApp` to httpuv's `startServer` function.
#
## ------------------------------------------------------------------------
HandlerList <- R6Class("HandlerList",
portable = FALSE,
class = FALSE,
public = list(
handlers = list(),
add = function(handler, key, tail = FALSE) {
if (!is.null(handlers[[key]]))
stop("Key ", key, " already in use")
newList <- structure(names=key, list(handler))
if (length(handlers) == 0)
handlers <<- newList
else if (tail)
handlers <<- c(handlers, newList)
else
handlers <<- c(newList, handlers)
},
remove = function(key) {
handlers[key] <<- NULL
},
clear = function() {
handlers <<- list()
},
invoke = function(...) {
for (handler in handlers) {
result <- handler(...)
if (!is.null(result))
return(result)
}
return(NULL)
}
)
)
HandlerManager <- R6Class("HandlerManager",
portable = FALSE,
class = FALSE,
public = list(
handlers = "HandlerList",
wsHandlers = "HandlerList",
initialize = function() {
handlers <<- HandlerList$new()
wsHandlers <<- HandlerList$new()
},
addHandler = function(handler, key, tail = FALSE) {
handlers$add(handler, key, tail)
},
removeHandler = function(key) {
handlers$remove(key)
},
addWSHandler = function(wsHandler, key, tail = FALSE) {
wsHandlers$add(wsHandler, key, tail)
},
removeWSHandler = function(key) {
wsHandlers$remove(key)
},
clear = function() {
handlers$clear()
wsHandlers$clear()
},
createHttpuvApp = function() {
list(
onHeaders = function(req) {
maxSize <- getOption('shiny.maxRequestSize') %OR% (5 * 1024 * 1024)
if (maxSize <= 0)
return(NULL)
reqSize <- 0
if (length(req$CONTENT_LENGTH) > 0)
reqSize <- as.numeric(req$CONTENT_LENGTH)
else if (length(req$HTTP_TRANSFER_ENCODING) > 0)
reqSize <- Inf
if (reqSize > maxSize) {
return(list(status = 413L,
headers = list(
'Content-Type' = 'text/plain'
),
body = 'Maximum upload size exceeded'))
}
else {
return(NULL)
}
},
call = .httpServer(
function (req) {
withLogErrors(handlers$invoke(req))
},
getOption('shiny.sharedSecret')
),
onWSOpen = function(ws) {
return(wsHandlers$invoke(ws))
}
)
},
.httpServer = function(handler, sharedSecret) {
filter <- getOption('shiny.http.response.filter')
if (is.null(filter))
filter <- function(req, response) response
function(req) {
if (!is.null(sharedSecret)
&& !identical(sharedSecret, req$HTTP_SHINY_SHARED_SECRET)) {
return(list(status=403,
body='<h1>403 Forbidden</h1><p>Shared secret mismatch</p>',
headers=list('Content-Type' = 'text/html')))
}
# Catch HEAD requests. For the purposes of handler functions, they
# should be treated like GET. The difference is that they shouldn't
# return a body in the http response.
head_request <- FALSE
if (identical(req$REQUEST_METHOD, "HEAD")) {
head_request <- TRUE
req$REQUEST_METHOD <- "GET"
}
response <- handler(req)
if (is.null(response))
response <- httpResponse(404, content="<h1>Not Found</h1>")
if (inherits(response, "httpResponse")) {
headers <- as.list(response$headers)
headers$'Content-Type' <- response$content_type
response <- filter(req, response)
if (head_request) {
headers$`Content-Length` <- nchar(response$content, type = "bytes")
return(list(
status = response$status,
body = "",
headers = headers
))
} else {
return(list(
status = response$status,
body = response$content,
headers = headers
))
}
} else {
# Assume it's a Rook-compatible response
return(response)
}
}
}
)
)
#
# ## Next steps
#
# See server.R and middleware-shiny.R to see actual implementation and usage of
# handlers in the context of Shiny.

57
R/modules.R Normal file
View File

@@ -0,0 +1,57 @@
# Creates an object whose $ and $<- pass through to the parent
# session, unless the name is matched in ..., in which case
# that value is returned instead. (See Decorator pattern.)
createSessionProxy <- function(parentSession, ...) {
e <- new.env(parent = emptyenv())
e$parent <- parentSession
e$overrides <- list(...)
structure(
e,
class = "session_proxy"
)
}
#' @export
`$.session_proxy` <- function(x, name) {
if (name %in% names(x[["overrides"]]))
x[["overrides"]][[name]]
else
x[["parent"]][[name]]
}
#' @export
`$<-.session_proxy` <- function(x, name, value) {
x[["parent"]][[name]] <- value
x
}
#' Invoke a Shiny module
#'
#' Shiny's module feature lets you break complicated UI and server logic into
#' smaller, self-contained pieces. Compared to large monolithic Shiny apps,
#' modules are easier to reuse and easier to reason about. See the article at
#' \url{http://shiny.rstudio.com/articles/modules.html} to learn more.
#'
#' @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
#' @param session Session from which to make a child scope (the default should
#' almost always be used)
#'
#' @return The return value, if any, from executing the module server function
#' @seealso \url{http://shiny.rstudio.com/articles/modules.html}
#'
#' @export
callModule <- function(module, id, ..., session = getDefaultReactiveDomain()) {
childScope <- session$makeScope(id)
withReactiveDomain(childScope, {
if (!is.function(module)) {
stop("module argument must be a function")
}
module(childScope$input, childScope$output, childScope, ...)
})
}

View File

@@ -4,20 +4,24 @@
# elements have the same priority, they are served according to their order in
# the queue." (http://en.wikipedia.org/wiki/Priority_queue)
PriorityQueue <- setRefClass(
PriorityQueue <- R6Class(
'PriorityQueue',
fields = list(
portable = FALSE,
class = FALSE,
public = list(
# Keys are priorities, values are subqueues (implemented as list)
.itemsByPriority = 'Map',
# Sorted vector (largest first)
.priorities = 'numeric'
),
methods = list(
# Enqueue an item, with the given priority level (must be integer). Higher
.priorities = numeric(0),
initialize = function() {
.itemsByPriority <<- Map$new()
},
# Enqueue an item, with the given priority level (must be integer). Higher
# priority numbers are dequeued earlier than lower.
enqueue = function(item, priority) {
priority <- normalizePriority(priority)
if (!(priority %in% .priorities)) {
.priorities <<- c(.priorities, priority)
.priorities <<- sort(.priorities, decreasing=TRUE)
@@ -30,14 +34,14 @@ PriorityQueue <- setRefClass(
}
return(invisible())
},
# Retrieve a single item by 1) priority number (highest first) and then 2)
# insertion order (first in, first out). If there are no items to be
# Retrieve a single item by 1) priority number (highest first) and then 2)
# insertion order (first in, first out). If there are no items to be
# dequeued, then NULL is returned. If it is necessary to distinguish between
# a NULL value and the empty case, call isEmpty() before dequeue().
dequeue = function() {
if (length(.priorities) == 0)
return(NULL)
maxPriority <- .priorities[[1]]
items <- .itemsByPriority$get(.key(maxPriority))
firstItem <- items[[1]]
@@ -67,17 +71,17 @@ PriorityQueue <- setRefClass(
)
normalizePriority <- function(priority) {
if (is.null(priority))
priority <- 0
# Cast integers to numeric to prevent any inconsistencies
if (is.integer(priority))
priority <- as.numeric(priority)
if (!is.numeric(priority))
stop('priority must be an integer or numeric')
# Check length
if (length(priority) == 0) {
warning('Zero-length priority vector was passed; using 0')
@@ -86,7 +90,7 @@ normalizePriority <- function(priority) {
warning('Priority has length > 1 and only the first element will be used')
priority <- priority[1]
}
# NA == 0
if (is.na(priority))
priority <- 0

283
R/progress.R Normal file
View File

@@ -0,0 +1,283 @@
#' Reporting progress (object-oriented API)
#'
#' Reports progress to the user during long-running operations.
#'
#' This package exposes two distinct programming APIs for working with
#' progress. \code{\link{withProgress}} and \code{\link{setProgress}}
#' together provide a simple function-based interface, while the
#' \code{Progress} reference class provides an object-oriented API.
#'
#' Instantiating a \code{Progress} object causes a progress panel to be
#' created, and it will be displayed the first time the \code{set}
#' method is called. Calling \code{close} will cause the progress panel
#' to be removed.
#'
#' \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.
#' }
#' }
#'
#' @param session The Shiny session object, as provided by
#' \code{shinyServer} to the server function.
#' @param min The value that represents the starting point of the
#' progress bar. Must be less tham \code{max}.
#' @param max The value that represents the end of the progress bar.
#' Must be greater than \code{min}.
#' @param message A single-element character vector; the message to be
#' displayed to the user, or \code{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 \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}.
#' @param value A numeric 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.
#' @param 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.
#' @param amount For the \code{inc()} method, a numeric value to increment the
#' progress bar.
#'
#' @examples
#' \dontrun{
#' # server.R
#' shinyServer(function(input, output, session) {
#' output$plot <- renderPlot({
#' progress <- shiny::Progress$new(session, min=1, max=15)
#' on.exit(progress$close())
#'
#' progress$set(message = 'Calculation in progress',
#' detail = 'This may take a while...')
#'
#' for (i in 1:15) {
#' progress$set(value = i)
#' Sys.sleep(0.5)
#' }
#' plot(cars)
#' })
#' })
#' }
#' @seealso \code{\link{withProgress}}
#' @format NULL
#' @usage NULL
#' @export
Progress <- R6Class(
'Progress',
portable = TRUE,
public = list(
initialize = function(session = getDefaultReactiveDomain(), min = 0, max = 1) {
if (is.null(session$progressStack))
stop("'session' is not a ShinySession object.")
private$session <- session
private$id <- paste(as.character(as.raw(stats::runif(8, min=0, max=255))), collapse='')
private$min <- min
private$max <- max
private$value <- NULL
private$closed <- FALSE
session$sendProgress('open', list(id = private$id))
},
set = function(value = NULL, message = NULL, detail = NULL) {
if (private$closed) {
warning("Attempting to set progress, but progress already closed.")
return()
}
if (is.null(value) || is.na(value)) {
value <- NULL
} else {
# Normalize value to number between 0 and 1
value <- min(1, max(0, (value - private$min) / (private$max - private$min)))
}
private$value <- value
data <- dropNulls(list(
id = private$id,
message = message,
detail = detail,
value = value
))
private$session$sendProgress('update', data)
},
inc = function(amount = 0.1, message = NULL, detail = NULL) {
value <- min(self$getValue() + amount, private$max)
self$set(value, message, detail)
},
getMin = function() private$min,
getMax = function() private$max,
# Return value (not the normalized 0-1 value, but in the original range)
getValue = function() {
private$value * (private$max - private$min) + private$min
},
close = function() {
if (private$closed) {
warning("Attempting to close progress, but progress already closed.")
return()
}
private$session$sendProgress('close', list(id = private$id))
private$closed <- TRUE
}
),
private = list(
session = 'environment',
id = character(0),
min = numeric(0),
max = numeric(0),
value = NULL,
closed = logical(0)
)
)
#' Reporting progress (functional API)
#'
#' Reports progress to the user during long-running operations.
#'
#' This package exposes two distinct programming APIs for working with progress.
#' Using \code{withProgress} with \code{incProgress} or \code{setProgress}
#' provide a simple function-based interface, while the \code{\link{Progress}}
#' reference class provides an object-oriented API.
#'
#' Use \code{withProgress} to wrap the scope of your work; doing so will cause a
#' new progress panel to be created, and it will be displayed the first time
#' \code{incProgress} or \code{setProgress} are called. When \code{withProgress}
#' exits, the corresponding progress panel will be removed.
#'
#' The \code{incProgress} function increments the status bar by a specified
#' amount, whereas the \code{setProgress} function sets it to a specific value,
#' and can also set the text displayed.
#'
#' Generally, \code{withProgress}/\code{incProgress}/\code{setProgress} should
#' be sufficient; the exception is if the work to be done is asynchronous (this
#' is not common) or otherwise cannot be encapsulated by a single scope. In that
#' case, you can use the \code{Progress} reference class.
#'
#' @param session The Shiny session object, as provided by \code{shinyServer} to
#' the server function. The default is to automatically find the session by
#' using the current reactive domain.
#' @param expr The work to be done. This expression should contain calls to
#' \code{setProgress}.
#' @param min The value that represents the starting point of the progress bar.
#' Must be less tham \code{max}. Default is 0.
#' @param max The value that represents the end of the progress bar. Must be
#' greater than \code{min}. Default is 1.
#' @param amount For \code{incProgress}, the amount to increment the status bar.
#' Default is 0.1.
#' @param env The environment in which \code{expr} should be evaluated.
#' @param quoted Whether \code{expr} is a quoted expression (this is not
#' common).
#' @param message A single-element character vector; the message to be displayed
#' to the user, or \code{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 \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}.
#' @param 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.
#'
#' @examples
#' \dontrun{
#' # server.R
#' shinyServer(function(input, output) {
#' output$plot <- renderPlot({
#' withProgress(message = 'Calculation in progress',
#' detail = 'This may take a while...', value = 0, {
#' for (i in 1:15) {
#' incProgress(1/15)
#' Sys.sleep(0.25)
#' }
#' })
#' plot(cars)
#' })
#' })
#' }
#' @seealso \code{\link{Progress}}
#' @rdname withProgress
#' @export
withProgress <- function(expr, min = 0, max = 1,
value = min + (max - min) * 0.1,
message = NULL, detail = NULL,
session = getDefaultReactiveDomain(),
env = parent.frame(), quoted = FALSE) {
if (!quoted)
expr <- substitute(expr)
if (is.null(session$progressStack))
stop("'session' is not a ShinySession object.")
p <- Progress$new(session, min = min, max = max)
session$progressStack$push(p)
on.exit({
session$progressStack$pop()
p$close()
})
p$set(value, message, detail)
eval(expr, env)
}
#' @rdname withProgress
#' @export
setProgress <- function(value = NULL, message = NULL, detail = NULL,
session = getDefaultReactiveDomain()) {
if (is.null(session$progressStack))
stop("'session' is not a ShinySession object.")
if (session$progressStack$size() == 0) {
warning('setProgress was called outside of withProgress; ignoring')
return()
}
session$progressStack$peek()$set(value, message, detail)
invisible()
}
#' @rdname withProgress
#' @export
incProgress <- function(amount = 0.1, message = NULL, detail = NULL,
session = getDefaultReactiveDomain()) {
if (is.null(session$progressStack))
stop("'session' is not a ShinySession object.")
if (session$progressStack$size() == 0) {
warning('incProgress was called outside of withProgress; ignoring')
return()
}
p <- session$progressStack$peek()
p$inc(amount, message, detail)
invisible()
}

119
R/react.R
View File

@@ -1,27 +1,29 @@
Context <- setRefClass(
Context <- R6Class(
'Context',
fields = list(
id = 'character',
.label = 'character', # For debug purposes
.invalidated = 'logical',
.invalidateCallbacks = 'list',
.flushCallbacks = 'list'
),
methods = list(
initialize = function(label='', type='other', prevId='') {
portable = FALSE,
class = FALSE,
public = list(
id = character(0),
.label = character(0), # For debug purposes
.invalidated = FALSE,
.invalidateCallbacks = list(),
.flushCallbacks = list(),
.domain = NULL,
initialize = function(domain, label='', type='other', prevId='') {
id <<- .getReactiveEnvironment()$nextId()
.invalidated <<- FALSE
.invalidateCallbacks <<- list()
.flushCallbacks <<- list()
.label <<- label
.graphCreateContext(id, label, type, prevId)
.domain <<- domain
.graphCreateContext(id, label, type, prevId, domain)
},
run = function(func) {
"Run the provided function under this context."
env <- .getReactiveEnvironment()
.graphEnterContext(id)
on.exit(.graphExitContext(id))
env$runWith(.self, func)
withReactiveDomain(.domain, {
env <- .getReactiveEnvironment()
.graphEnterContext(id)
on.exit(.graphExitContext(id), add = TRUE)
env$runWith(self, func)
})
},
invalidate = function() {
"Invalidate this context. It will immediately call the callbacks
@@ -30,10 +32,11 @@ Context <- setRefClass(
return()
.invalidated <<- TRUE
.graphInvalidate(id)
.graphInvalidate(id, .domain)
lapply(.invalidateCallbacks, function(func) {
func()
})
.invalidateCallbacks <<- list()
NULL
},
onInvalidate = function(func) {
@@ -49,7 +52,10 @@ Context <- setRefClass(
addPendingFlush = function(priority) {
"Tell the reactive environment that this context should be flushed the
next time flushReact() called."
.getReactiveEnvironment()$addPendingFlush(.self, priority)
if (!is.null(.domain)) {
.domain$incrementBusyCount()
}
.getReactiveEnvironment()$addPendingFlush(self, priority)
},
onFlush = function(func) {
"Register a function to be called when this context is flushed."
@@ -57,33 +63,32 @@ Context <- setRefClass(
},
executeFlushCallbacks = function() {
"For internal use only."
lapply(.flushCallbacks, function(func) {
withCallingHandlers({
func()
}, warning = function(e) {
# TODO: Callbacks in app
}, error = function(e) {
# TODO: Callbacks in app
})
on.exit({
if (!is.null(.domain)) {
.domain$decrementBusyCount()
}
}, add = TRUE)
lapply(.flushCallbacks, function(flushCallback) {
flushCallback()
})
}
)
)
ReactiveEnvironment <- setRefClass(
ReactiveEnvironment <- R6Class(
'ReactiveEnvironment',
fields = list(
.currentContext = 'ANY',
.nextId = 'integer',
portable = FALSE,
class = FALSE,
public = list(
.currentContext = NULL,
.nextId = 0L,
.pendingFlush = 'PriorityQueue',
.inFlush = 'logical'
),
methods = list(
.inFlush = FALSE,
initialize = function() {
.currentContext <<- NULL
.nextId <<- 0L
.pendingFlush <<- PriorityQueue$new()
.inFlush <<- FALSE
},
nextId = function() {
.nextId <<- .nextId + 1L
@@ -91,17 +96,21 @@ ReactiveEnvironment <- setRefClass(
},
currentContext = function() {
if (is.null(.currentContext)) {
stop('Operation not allowed without an active reactive context. ',
'(You tried to do something that can only be done from inside a ',
'reactive function.)')
if (isTRUE(getOption('shiny.suppressMissingContextError'))) {
return(getDummyContext())
} else {
stop('Operation not allowed without an active reactive context. ',
'(You tried to do something that can only be done from inside a ',
'reactive expression or observer.)')
}
}
return(.currentContext)
},
runWith = function(ctx, func) {
runWith = function(ctx, contextFunc) {
old.ctx <- .currentContext
.currentContext <<- ctx
on.exit(.currentContext <<- old.ctx)
shinyCallingHandlers(func())
contextFunc()
},
addPendingFlush = function(ctx, priority) {
.pendingFlush$enqueue(ctx, priority)
@@ -120,10 +129,14 @@ ReactiveEnvironment <- setRefClass(
)
)
.reactiveEnvironment <- ReactiveEnvironment$new()
.getReactiveEnvironment <- function() {
.reactiveEnvironment
}
.getReactiveEnvironment <- local({
reactiveEnvironment <- NULL
function() {
if (is.null(reactiveEnvironment))
reactiveEnvironment <<- ReactiveEnvironment$new()
return(reactiveEnvironment)
}
})
# Causes any pending invalidations to run.
flushReact <- function() {
@@ -135,3 +148,15 @@ flushReact <- function() {
getCurrentContext <- function() {
.getReactiveEnvironment()$currentContext()
}
getDummyContext <- function() {}
local({
dummyContext <- NULL
getDummyContext <<- function() {
if (is.null(dummyContext)) {
dummyContext <<- Context$new(getDefaultReactiveDomain(), '[none]',
type='isolate')
}
return(dummyContext)
}
})

255
R/reactive-domains.R Normal file
View File

@@ -0,0 +1,255 @@
#' @include globals.R
NULL
#
# Over the last few months we've seen a number of cases where it'd be helpful
# for objects that are instantiated within a Shiny app to know what Shiny
# session they are "owned" by. I put "owned" in quotes because there isn't a
# built-in notion of object ownership in Shiny today, any more than there is a
# notion of one object owning another in R.
#
# But it's intuitive to everyone, I think, that the outputs for a session are
# owned by that session, and any logic that is executed as part of the output
# is done on behalf of that session. And it seems like in the vast majority of
# cases, observers that are created inside a shinyServer function (i.e. one per
# session) are also intuitively owned by the session that's starting up.
#
# This notion of ownership is important/helpful for a few scenarios that have
# come up in recent months:
#
# 1. The showcase mode that Jonathan implemented recently highlights
# observers/reactives as they execute. In order for sessions to only receive
# highlights for their own code execution, we need to know which sessions own
# which observers. 2. We've seen a number of apps crash out when observers
# outlive their sessions and then try to do things with their sessions (the
# most common error message was something like "Can't write to a closed
# websocket", but we now silently ignore writes to closed websockets). It'd be
# convenient for the default behavior of observers to be that they don't
# outlive their parent sessions. 3. The reactive log visualizer currently
# visualizes all reactivity in the process; it would be great if by default it
# only visualized the current session. 4. When an observer has an error, it
# would be great to be able to send the error to the session so it can do its
# own handling (such as sending the error info to the client so the user can be
# notified). 5. Shiny Server Pro wants to show the admin how much time is being
# spent servicing each session.
#
# So what are the rules for establishing ownership?
#
# 1. Define the "current domain" as a global variable whose value will own any
# newly created observer (by default). A domain is a reference class or
# environment that contains the functions `onEnded(callback)`, `isEnded()`, and
# `reactlog(logEntry)`.
#
## ------------------------------------------------------------------------
createMockDomain <- function() {
callbacks <- list()
ended <- FALSE
domain <- new.env(parent = emptyenv())
domain$onEnded <- function(callback) {
callbacks <<- c(callbacks, callback)
}
domain$isEnded <- function() {
ended
}
domain$reactlog <- function(logEntry) NULL
domain$end <- function() {
if (!ended) {
ended <<- TRUE
lapply(callbacks, do.call, list())
}
invisible()
}
domain$incrementBusyCount <- function() NULL
domain$decrementBusyCount <- function() NULL
return(domain)
}
#
# 2. The initial value of "current domain" is null.
#
## ------------------------------------------------------------------------
.globals$domain <- NULL
#
# 3. Objects that can be owned include observers, reactive expressions,
# invalidateLater instances, reactiveTimer instances. Whenever one of these is
# created, by default its owner will be the current domain.
#
## ------------------------------------------------------------------------
#' @name domains
#' @rdname domains
#' @export
getDefaultReactiveDomain <- function() {
.globals$domain
}
#
# 4. While a session is being created and the shinyServer function is executed,
# the current domain is set to the new session. When the shinyServer function
# is done executing, the previous value of the current domain is restored. This
# is made foolproof using a `withReactiveDomain` function.
#
## ------------------------------------------------------------------------
#' @rdname domains
#' @export
withReactiveDomain <- function(domain, expr) {
oldValue <- .globals$domain
.globals$domain <- domain
on.exit(.globals$domain <- oldValue)
expr
}
#
# 5. While an observer or reactive expression is executing, the current domain
# is set to the owner of the observer. When the observer completes, the
# previous value of the current domain is restored.
#
# 6. Note that once created, an observer/reactive expression belongs to the
# same domain forever, regardless of how many times it is invalidated and
# re-executed, and regardless of what caused the invalidation to happen.
#
# 7. When a session ends, any observers that it owns are suspended, any
# invalidateLater/reactiveTimers are stopped.
#
## ------------------------------------------------------------------------
#' @rdname domains
#' @export
onReactiveDomainEnded <- function(domain, callback, failIfNull = FALSE) {
if (is.null(domain)) {
if (isTRUE(failIfNull))
stop("onReactiveDomainEnded called with null domain and failIfNull=TRUE")
else
return()
}
domain$onEnded(callback)
}
#
# 8. If an uncaught error occurs while executing an observer, the session gets
# a chance to handle it. I suppose the default behavior would be to send the
# message to the client if possible, and then perhaps end the session (or not,
# I could argue either way).
#
# The basic idea here is inspired by Node.js domains, which you can think of as
# a way to track execution contexts across callback- or listener-oriented
# asynchronous code. They use it to unify error handling code across a graph of
# related objects. Our domains will be to unify both lifetime and error
# handling across a graph of related reactive primitives.
#
# (You could imagine that as a client update is being processed, the session
# associated with that client would become the current domain. IIRC this is how
# showcase mode is implemented today. I don't think this would cover any cases
# not covered by rule 5 above, and the absence of rule 5 would leave cases that
# this rule would not cover.)
#
# Pitfalls/open issues:
#
# 1. Our current approach has the issue of observers staying alive longer than
# they ought to. This proposal introduces the opposite risk: that
# observers/invalidateLater/reactiveTimer instances, having implicitly been
# assigned a parent, are suspended/disposed earlier than they ought to have
# been. I find this especially worrisome for invalidateLater/reactiveTimer,
# which will often be called in a reactive expression, and thus execute under
# unpredictable circumstances. Perhaps those should continue to accept an
# explicit "session=" parameter that the user is warned about if they don't
# provide a value.
#
# 2. Are there situations where it is ambiguous what the right thing to do is,
# and we should warn/error to ask the user to provide a domain explicitly?
#
## ------------------------------------------------------------------------
#' Reactive domains
#'
#' Reactive domains are a mechanism for establishing ownership over reactive
#' primitives (like reactive expressions and observers), even if the set of
#' reactive primitives is dynamically created. This is useful for lifetime
#' management (i.e. destroying observers when the Shiny session that created
#' them ends) and error handling.
#'
#' At any given time, there can be either a single "default" reactive domain
#' object, or none (i.e. the reactive domain object is \code{NULL}). You can
#' access the current default reactive domain by calling
#' \code{getDefaultReactiveDomain}.
#'
#' Unless you specify otherwise, newly created observers and reactive
#' expressions will be assigned to the current default domain (if any). You can
#' override this assignment by providing an explicit \code{domain} argument to
#' \code{\link{reactive}} or \code{\link{observe}}.
#'
#' For advanced usage, it's possible to override the default domain using
#' \code{withReactiveDomain}. The \code{domain} argument will be made the
#' default domain while \code{expr} is evaluated.
#'
#' Implementers of new reactive primitives can use \code{onReactiveDomainEnded}
#' as a convenience function for registering callbacks. If the reactive domain
#' is \code{NULL} and \code{failIfNull} is \code{FALSE}, then the callback will
#' never be invoked.
#'
#' @name domains
#' @param domain A valid domain object (for example, a Shiny session), or
#' \code{NULL}
#' @param expr An expression to evaluate under \code{domain}
#' @param callback A callback function to be invoked
#' @param failIfNull If \code{TRUE} then an error is given if the \code{domain}
#' is \code{NULL}
NULL
#
# Example 1
# ---
# ```
# obs1 <- observe({
# })
# shinyServer(function(input, output) {
# obs2 <- observe({
# obs3 <- observe({
# })
# })
# })
# # obs1 would have no domain, obs2 and obs3 would be owned by the session
# ```
#
# Example 2
# ---
# ```
# globalValues <- reactiveValues(broadcast="")
# shinyServer(function(input, output) {
# sessionValues <- reactiveValues()
# output$messageOutput <- renderText({
# globalValues$broadcast
# obs1 <- observe({...})
# })
# observe({
# if (input$goButton == 0) return()
# isolate( globalValues$broadcast <- input$messageInput )
# })
# })
# # The observer behind messageOutput would be owned by the session,
# # as would all the many instances of obs1 that were created.
# ```
# ---
#
# Example 3
# ---
# ```
# rexpr1 <- reactive({
# invalidateLater(1000)
# obs1 <- observe({...})
# })
# observeSomething <- function() {
# obs2 <- observe({...})
# })
# shinyServer(function(input, output) {
# obs3 <- observe({
# observeSomething()
# rexpr1()
# })
# })
# # rexpr1, the invalidateLater call, and obs1 would all have no owner;
# # obs2 and obs3 would be owned by the session.
# ```

File diff suppressed because it is too large Load Diff

617
R/render-plot.R Normal file
View File

@@ -0,0 +1,617 @@
#' Plot Output
#'
#' Renders a reactive plot that is suitable for assigning to an \code{output}
#' slot.
#'
#' The corresponding HTML output tag should be \code{div} or \code{img} and have
#' the CSS class name \code{shiny-plot-output}.
#'
#' @section Interactive plots:
#'
#' With ggplot2 graphics, the code in \code{renderPlot} should return a ggplot
#' object; if instead the code prints the ggplot2 object with something like
#' \code{print(p)}, then the coordinates for interactive graphics will not be
#' properly scaled to the data space.
#'
#' See \code{\link{plotOutput}} for more information about interactive plots.
#'
#' @seealso For the corresponding client-side output function, and example
#' usage, see \code{\link{plotOutput}}. For more details on how the plots are
#' generated, and how to control the output, see \code{\link{plotPNG}}.
#'
#' @param expr An expression that generates a plot.
#' @param width,height The width/height of the rendered plot, in pixels; or
#' \code{'auto'} to use the \code{offsetWidth}/\code{offsetHeight} of the HTML
#' element that is bound to this plot. You can also pass in a function that
#' returns the width/height in pixels or \code{'auto'}; in the body of the
#' function you may reference reactive values and functions. When rendering an
#' inline plot, you must provide numeric values (in pixels) to both
#' \code{width} and \code{height}.
#' @param res Resolution of resulting plot, in pixels per inch. This value is
#' passed to \code{\link{png}}. Note that this affects the resolution of PNG
#' rendering in R; it won't change the actual ppi of the browser.
#' @param ... Arguments to be passed through to \code{\link[grDevices]{png}}.
#' These can be used to set the width, height, background color, etc.
#' @param env The environment in which to evaluate \code{expr}.
#' @param quoted Is \code{expr} a quoted expression (with \code{quote()})? This
#' is useful if you want to save an expression in a variable.
#' @param func A function that generates a plot (deprecated; use \code{expr}
#' instead).
#'
#' @export
renderPlot <- function(expr, width='auto', height='auto', res=72, ...,
env=parent.frame(), quoted=FALSE, func=NULL) {
# This ..stacktraceon is matched by a ..stacktraceoff.. when plotFunc
# is called
installExprFunction(expr, "func", env, quoted, ..stacktraceon = TRUE)
args <- list(...)
if (is.function(width))
widthWrapper <- reactive({ width() })
else
widthWrapper <- NULL
if (is.function(height))
heightWrapper <- reactive({ height() })
else
heightWrapper <- NULL
# If renderPlot isn't going to adapt to the height of the div, then the
# div needs to adapt to the height of renderPlot. By default, plotOutput
# sets the height to 400px, so to make it adapt we need to override it
# with NULL.
outputFunc <- plotOutput
if (!identical(height, 'auto')) formals(outputFunc)['height'] <- list(NULL)
return(markRenderFunction(outputFunc, function(shinysession, name, ...) {
if (!is.null(widthWrapper))
width <- widthWrapper()
if (!is.null(heightWrapper))
height <- heightWrapper()
# Note that these are reactive calls. A change to the width and height
# will inherently cause a reactive plot to redraw (unless width and
# height were explicitly specified).
prefix <- 'output_'
if (width == 'auto')
width <- shinysession$clientData[[paste(prefix, name, '_width', sep='')]];
if (height == 'auto')
height <- shinysession$clientData[[paste(prefix, name, '_height', sep='')]];
if (is.null(width) || is.null(height) || width <= 0 || height <= 0)
return(NULL)
# Resolution multiplier
pixelratio <- shinysession$clientData$pixelratio
if (is.null(pixelratio))
pixelratio <- 1
coordmap <- NULL
plotFunc <- function() {
# Actually perform the plotting
result <- withVisible(func())
coordmap <<- NULL
if (result$visible) {
# Use capture.output to squelch printing to the actual console; we
# are only interested in plot output
# Special case for ggplot objects - need to capture coordmap
if (inherits(result$value, "ggplot")) {
utils::capture.output(coordmap <<- getGgplotCoordmap(result$value, pixelratio))
} else {
# This ..stacktraceon.. negates the ..stacktraceoff.. that wraps the
# call to plotFunc
utils::capture.output(..stacktraceon..(print(result$value)))
}
}
if (is.null(coordmap)) {
coordmap <<- getPrevPlotCoordmap(width, height)
}
}
# This ..stacktraceoff.. is matched by the `func` function's
# wrapFunctionLabel(..stacktraceon=TRUE) call near the beginning of
# renderPlot, and by the ..stacktraceon.. in plotFunc where ggplot objects
# are printed
outfile <- ..stacktraceoff..(
do.call(plotPNG, c(plotFunc, width=width*pixelratio,
height=height*pixelratio, res=res*pixelratio, args))
)
on.exit(unlink(outfile))
# A list of attributes for the img
res <- list(
src=shinysession$fileUrl(name, outfile, contentType='image/png'),
width=width, height=height, coordmap=coordmap
)
# Get error message if present (from attribute on the coordmap)
error <- attr(coordmap, "error", exact = TRUE)
if (!is.null(error)) {
res$error <- error
}
res
}))
}
# The coordmap extraction functions below return something like the examples
# below. For base graphics:
# plot(mtcars$wt, mtcars$mpg)
# str(getPrevPlotCoordmap(400, 300))
# List of 1
# $ :List of 4
# ..$ domain :List of 4
# .. ..$ left : num 1.36
# .. ..$ right : num 5.58
# .. ..$ bottom: num 9.46
# .. ..$ top : num 34.8
# ..$ range :List of 4
# .. ..$ left : num 50.4
# .. ..$ right : num 373
# .. ..$ bottom: num 199
# .. ..$ top : num 79.6
# ..$ log :List of 2
# .. ..$ x: NULL
# .. ..$ y: NULL
# ..$ mapping: Named list()
#
# For ggplot2, it might be something like:
# p <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
# str(getGgplotCoordmap(p, 1))
# List of 1
# $ :List of 10
# ..$ panel : int 1
# ..$ row : int 1
# ..$ col : int 1
# ..$ panel_vars: Named list()
# ..$ scale_x : int 1
# ..$ scale_y : int 1
# ..$ log :List of 2
# .. ..$ x: NULL
# .. ..$ y: NULL
# ..$ domain :List of 4
# .. ..$ left : num 1.32
# .. ..$ right : num 5.62
# .. ..$ bottom: num 9.22
# .. ..$ top : num 35.1
# ..$ mapping :List of 2
# .. ..$ x: chr "wt"
# .. ..$ y: chr "mpg"
# ..$ range :List of 4
# .. ..$ left : num 40.8
# .. ..$ right : num 446
# .. ..$ bottom: num 263
# .. ..$ top : num 14.4
#
# With a faceted ggplot2 plot, the outer list contains two objects, each of
# which represents one panel. In this example, there is one panelvar, but there
# can be up to two of them.
# mtc <- mtcars
# mtc$am <- factor(mtc$am)
# p <- ggplot(mtcars, aes(wt, mpg)) + geom_point() + facet_wrap(~ am)
# str(getGgplotCoordmap(p, 1))
# List of 2
# $ :List of 10
# ..$ panel : int 1
# ..$ row : int 1
# ..$ col : int 1
# ..$ panel_vars:List of 1
# .. ..$ panelvar1: Factor w/ 2 levels "0","1": 1
# ..$ scale_x : int 1
# ..$ scale_y : int 1
# ..$ log :List of 2
# .. ..$ x: NULL
# .. ..$ y: NULL
# ..$ domain :List of 4
# .. ..$ left : num 1.32
# .. ..$ right : num 5.62
# .. ..$ bottom: num 9.22
# .. ..$ top : num 35.1
# ..$ mapping :List of 3
# .. ..$ x : chr "wt"
# .. ..$ y : chr "mpg"
# .. ..$ panelvar1: chr "am"
# ..$ range :List of 4
# .. ..$ left : num 45.6
# .. ..$ right : num 317
# .. ..$ bottom: num 251
# .. ..$ top : num 35.7
# $ :List of 10
# ..$ panel : int 2
# ..$ row : int 1
# ..$ col : int 2
# ..$ panel_vars:List of 1
# .. ..$ panelvar1: Factor w/ 2 levels "0","1": 2
# ..$ scale_x : int 1
# ..$ scale_y : int 1
# ..$ log :List of 2
# .. ..$ x: NULL
# .. ..$ y: NULL
# ..$ domain :List of 4
# .. ..$ left : num 1.32
# .. ..$ right : num 5.62
# .. ..$ bottom: num 9.22
# .. ..$ top : num 35.1
# ..$ mapping :List of 3
# .. ..$ x : chr "wt"
# .. ..$ y : chr "mpg"
# .. ..$ panelvar1: chr "am"
# ..$ range :List of 4
# .. ..$ left : num 322
# .. ..$ right : num 594
# .. ..$ bottom: num 251
# .. ..$ top : num 35.7
# Get a coordmap for the previous plot made with base graphics.
# Requires width and height of output image, in pixels.
# Must be called before the graphics device is closed.
getPrevPlotCoordmap <- function(width, height) {
usrCoords <- graphics::par('usr')
usrBounds <- usrCoords
if (graphics::par('xlog')) {
usrBounds[c(1,2)] <- 10 ^ usrBounds[c(1,2)]
}
if (graphics::par('ylog')) {
usrBounds[c(3,4)] <- 10 ^ usrBounds[c(3,4)]
}
# Wrapped in double list because other types of plots can have multiple panels.
list(list(
# Bounds of the plot area, in data space
domain = list(
left = usrCoords[1],
right = usrCoords[2],
bottom = usrCoords[3],
top = usrCoords[4]
),
# The bounds of the plot area, in DOM pixels
range = list(
left = graphics::grconvertX(usrBounds[1], 'user', 'nfc') * width,
right = graphics::grconvertX(usrBounds[2], 'user', 'nfc') * width,
bottom = (1-graphics::grconvertY(usrBounds[3], 'user', 'nfc')) * height - 1,
top = (1-graphics::grconvertY(usrBounds[4], 'user', 'nfc')) * height - 1
),
log = list(
x = if (graphics::par('xlog')) 10 else NULL,
y = if (graphics::par('ylog')) 10 else NULL
),
# We can't extract the original variable names from a base graphic.
# `mapping` is an empty _named_ list, so that it is converted to an object
# (not an array) in JSON.
mapping = list(x = NULL)[0]
))
}
# Print a ggplot object and return a coordmap for it.
getGgplotCoordmap <- function(p, pixelratio) {
if (!inherits(p, "ggplot"))
return(NULL)
# A modified version of print.ggplot which returns the built ggplot object as
# well as the gtable grob. This overrides the ggplot::print.ggplot method, but
# only within the context of getGgplotCoordmap. The reason this needs to be an
# (pseudo) S3 method is so that, if an object has a class in addition to
# ggplot, and there's a print method for that class, that we won't override
# that method.
# https://github.com/rstudio/shiny/issues/841
print.ggplot <- function(x) {
grid::grid.newpage()
build <- ggplot2::ggplot_build(x)
gtable <- ggplot2::ggplot_gtable(build)
grid::grid.draw(gtable)
list(
build = build,
gtable = gtable
)
}
# Given the name of a generic function and an object, return the class name
# for the method that would be used on the object.
which_method <- function(generic, x) {
classes <- class(x)
method_names <- paste(generic, classes, sep = ".")
idx <- which(method_names %in% utils::methods(generic))
if (length(idx) == 0)
return(NULL)
# Return name of first class with matching method
classes[idx[1]]
}
# Given a built ggplot object, return x and y domains (data space coords) for
# each panel.
find_panel_info <- function(b) {
layout <- b$panel$layout
# Convert factor to numbers
layout$PANEL <- as.integer(as.character(layout$PANEL))
# Names of facets
facet <- b$plot$facet
facet_vars <- NULL
if (inherits(facet, "grid")) {
facet_vars <- vapply(c(facet$cols, facet$rows), as.character, character(1))
} else if (inherits(facet, "wrap")) {
facet_vars <- vapply(facet$facets, as.character, character(1))
}
# Iterate over each row in the layout data frame
lapply(seq_len(nrow(layout)), function(i) {
# Slice out one row
l <- layout[i, ]
scale_x <- l$SCALE_X
scale_y <- l$SCALE_Y
mapping <- find_plot_mappings(b)
# For each of the faceting variables, get the value of that variable in
# the current panel. Default to empty _named_ list so that it's sent as a
# JSON object, not array.
panel_vars <- list(a = NULL)[0]
for (i in seq_along(facet_vars)) {
var_name <- facet_vars[[i]]
vname <- paste0("panelvar", i)
mapping[[vname]] <- var_name
panel_vars[[vname]] <- l[[var_name]]
}
list(
panel = l$PANEL,
row = l$ROW,
col = l$COL,
panel_vars = panel_vars,
scale_x = scale_x,
scale_y = scale_x,
log = check_log_scales(b, scale_x, scale_y),
domain = find_panel_domain(b, l$PANEL, scale_x, scale_y),
mapping = mapping
)
})
}
# Given a single range object (representing the data domain) from a built
# ggplot object, return the domain.
find_panel_domain <- function(b, panel_num, scalex_num = 1, scaley_num = 1) {
range <- b$panel$ranges[[panel_num]]
res <- list(
left = range$x.range[1],
right = range$x.range[2],
bottom = range$y.range[1],
top = range$y.range[2]
)
# Check for reversed scales
xscale <- b$panel$x_scales[[scalex_num]]
yscale <- b$panel$y_scales[[scaley_num]]
if (!is.null(xscale$trans) && xscale$trans$name == "reverse") {
res$left <- -res$left
res$right <- -res$right
}
if (!is.null(yscale$trans) && yscale$trans$name == "reverse") {
res$top <- -res$top
res$bottom <- -res$bottom
}
res
}
# Given built ggplot object, return object with the log base for x and y if
# there are log scales or coord transforms.
check_log_scales <- function(b, scalex_num = 1, scaley_num = 1) {
# Given a vector of transformation names like c("log-10", "identity"),
# return the first log base, like 10. If none are present, return NULL.
extract_log_base <- function(names) {
names <- names[grepl("^log-", names)]
if (length(names) == 0)
return(NULL)
names <- names[1]
as.numeric(sub("^log-", "", names))
}
# Look for log scales and log coord transforms. People shouldn't use both.
x_names <- character(0)
y_names <- character(0)
# Continuous scales have a trans; discrete ones don't
if (!is.null(b$panel$x_scales[[scalex_num]]$trans))
x_names <- b$panel$x_scales[[scalex_num]]$trans$name
if (!is.null(b$panel$y_scales[[scaley_num]]$trans))
y_names <- b$panel$y_scales[[scaley_num]]$trans$name
coords <- b$plot$coordinates
if (!is.null(coords$trans)) {
if (!is.null(coords$trans$x))
x_names <- c(x_names, coords$trans$x$name)
if (!is.null(coords$trans$y))
y_names <- c(y_names, coords$trans$y$name)
}
# Keep only scale/trans names that start with "log-"
x_names <- x_names[grepl("^log-", x_names)]
y_names <- y_names[grepl("^log-", y_names)]
# Extract the log base from the trans name -- a string like "log-10".
list(
x = extract_log_base(x_names),
y = extract_log_base(y_names)
)
}
# Given a built ggplot object, return a named list of variables mapped to x
# and y. This function will be called for each panel, but in practice the
# result is always the same across panels, so we'll cache the result.
mappings_cache <- NULL
find_plot_mappings <- function(b) {
if (!is.null(mappings_cache))
return(mappings_cache)
# lapply'ing as.character results in unexpected behavior for expressions
# like `wt/2`. This works better.
mappings <- as.list(as.character(b$plot$mapping))
# If x or y mapping is missing, look in each layer for mappings and return
# the first one.
missing_mappings <- setdiff(c("x", "y"), names(mappings))
if (length(missing_mappings) != 0) {
# Grab mappings for each layer
layer_mappings <- lapply(b$plot$layers, function(layer) {
lapply(layer$mapping, as.character)
})
# Get just the first x or y value in the combined list of plot and layer
# mappings.
mappings <- c(list(mappings), layer_mappings)
mappings <- Reduce(x = mappings, init = list(x = NULL, y = NULL),
function(init, m) {
if (is.null(init$x) && !is.null(m$x)) init$x <- m$x
if (is.null(init$y) && !is.null(m$y)) init$y <- m$y
init
}
)
}
mappings_cache <<- mappings
mappings
}
# Given a gtable object, return the x and y ranges (in pixel dimensions)
find_panel_ranges <- function(g, pixelratio) {
# Given a vector of unit objects, return logical vector indicating which ones
# are "null" units. These units use the remaining available width/height --
# that is, the space not occupied by elements that have an absolute size.
is_null_unit <- function(x) {
# A vector of units can be either a list of individual units (a unit.list
# object), each with their own set of attributes, or an atomic vector with
# one set of attributes. ggplot2 switched from the former (in version
# 1.0.1) to the latter. We need to make sure that we get the correct
# result in both cases.
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")
})
} else {
# For later versions of ggplot2
attr(x, "unit", exact = TRUE) == "null"
}
}
# Convert a unit (or vector of units) to a numeric vector of pixel sizes
h_px <- function(x) as.numeric(grid::convertHeight(x, "native"))
w_px <- function(x) as.numeric(grid::convertWidth(x, "native"))
# Given a vector of relative sizes (in grid units), and a function for
# converting grid units to numeric pixels, return a numeric vector of
# pixel sizes.
find_px_sizes <- function(rel_sizes, unit_to_px) {
# Total pixels (in height or width)
total_px <- unit_to_px(grid::unit(1, "npc"))
# Calculate size of all panel(s) together. Panels (and only panels) have
# null size.
null_idx <- is_null_unit(rel_sizes)
# All the absolute heights. At this point, null heights are 0. We need to
# calculate them separately and add them in later.
px_sizes <- unit_to_px(rel_sizes)
# Total size for panels is image size minus absolute (non-panel) elements
panel_px_total <- total_px - sum(px_sizes)
# Divide up the total panel size up into the panels (scaled by size)
panel_sizes_rel <- as.numeric(rel_sizes[null_idx])
panel_sizes_rel <- panel_sizes_rel / sum(panel_sizes_rel)
px_sizes[null_idx] <- panel_px_total * panel_sizes_rel
abs(px_sizes)
}
px_heights <- find_px_sizes(g$heights, h_px)
px_widths <- find_px_sizes(g$widths, w_px)
# Convert to absolute pixel positions
x_pos <- cumsum(px_widths)
y_pos <- cumsum(px_heights)
# Match up the pixel dimensions to panels
layout <- g$layout
# For panels:
# * For facet_wrap, they'll be named "panel-1", "panel-2", etc.
# * For no facet or facet_grid, they'll just be named "panel". For
# facet_grid, we need to re-order the layout table. Assume that panel
# numbers go from left to right, then next row.
# Assign a number to each panel, corresponding to PANEl in the built ggplot
# object.
layout <- layout[grepl("^panel", layout$name), ]
layout <- layout[order(layout$t, layout$l), ]
layout$panel <- seq_len(nrow(layout))
# When using a HiDPI client on a Linux server, the pixel
# dimensions are doubled, so we have to divide the dimensions by
# `pixelratio`. When a HiDPI client is used on a Mac server (with
# the quartz device), the pixel dimensions _aren't_ doubled, even though
# the image has double size. In the latter case we don't have to scale the
# numbers down.
pix_ratio <- 1
if (!grepl("^quartz", names(grDevices::dev.cur()))) {
pix_ratio <- pixelratio
}
# Return list of lists, where each inner list has left, right, top, bottom
# values for a panel
lapply(seq_len(nrow(layout)), function(i) {
p <- layout[i, , drop = FALSE]
list(
left = x_pos[p$l - 1] / pix_ratio,
right = x_pos[p$r] / pix_ratio,
bottom = y_pos[p$b] / pix_ratio,
top = y_pos[p$t - 1] / pix_ratio
)
})
}
# If print(p) gets dispatched to print.ggplot(p), attempt to extract coordmap.
# If dispatched to another method, just print the object and don't attempt to
# extract the coordmap. This can happen if there's another print method that
# takes precedence.
if (identical(which_method("print", p), "ggplot")) {
res <- print(p)
tryCatch({
# Get info from built ggplot object
info <- find_panel_info(res$build)
# Get ranges from gtable - it's possible for this to return more elements than
# info, because it calculates positions even for panels that aren't present.
# This can happen with facet_wrap.
ranges <- find_panel_ranges(res$gtable, pixelratio)
for (i in seq_along(info)) {
info[[i]]$range <- ranges[[i]]
}
return(info)
}, error = function(e) {
# If there was an error extracting info from the ggplot object, just return
# a list with the error message.
return(structure(list(), error = e$message))
})
} else {
print(p)
return(list())
}
}

59
R/render-table.R Normal file
View File

@@ -0,0 +1,59 @@
#' Table Output
#'
#' Creates a reactive table that is suitable for assigning to an \code{output}
#' slot.
#'
#' The corresponding HTML output tag should be \code{div} and have the CSS class
#' name \code{shiny-html-output}.
#'
#' @param expr An expression that returns an R object that can be used with
#' \code{\link[xtable]{xtable}}.
#' @param ... Arguments to be passed through to \code{\link[xtable]{xtable}} and
#' \code{\link[xtable]{print.xtable}}.
#' @param env The environment in which to evaluate \code{expr}.
#' @param quoted Is \code{expr} a quoted expression (with \code{quote()})? This
#' is useful if you want to save an expression in a variable.
#' @param func A function that returns an R object that can be used with
#' \code{\link[xtable]{xtable}} (deprecated; use \code{expr} instead).
#'
#' @export
renderTable <- function(expr, ..., env=parent.frame(), quoted=FALSE, func=NULL) {
if (!is.null(func)) {
shinyDeprecated(msg="renderTable: argument 'func' is deprecated. Please use 'expr' instead.")
} else {
installExprFunction(expr, "func", env, quoted)
}
markRenderFunction(tableOutput, function() {
classNames <- getOption('shiny.table.class') %OR% 'data table table-bordered table-condensed'
data <- func()
if (is.null(data) || identical(data, data.frame()))
return("")
# Separate the ... args to pass to xtable() vs print.xtable()
dots <- list(...)
xtable_argnames <- setdiff(names(formals(xtable)), c("x", "..."))
xtable_args <- dots[intersect(names(dots), xtable_argnames)]
non_xtable_args <- dots[setdiff(names(dots), xtable_argnames)]
# Call xtable with its args
xtable_res <- do.call(xtable, c(list(data), xtable_args))
# Set up print args
print_args <- list(
xtable_res,
type = 'html',
html.table.attributes = paste('class="', htmlEscape(classNames, TRUE),
'"', sep='')
)
print_args <- c(print_args, non_xtable_args)
return(paste(
utils::capture.output(
do.call(print, print_args)
),
collapse="\n"
))
})
}

View File

@@ -1,124 +1,35 @@
#' Run a Shiny application from https://gist.github.com
#'
#' Download and launch a Shiny application that is hosted on GitHub as a gist.
#'
#' @param gist The identifier of the gist. For example, if the gist is
#' https://gist.github.com/jcheng5/3239667, then \code{3239667},
#' \code{'3239667'}, and \code{'https://gist.github.com/jcheng5/3239667'}
#' are all valid values.
#' @param port The TCP port that the application should listen on. Defaults to
#' choosing a random port.
#' @param launch.browser If true, the system's default web browser will be
#' launched automatically after the app is started. Defaults to true in
#' interactive sessions only.
#'
#' @examples
#' \dontrun{
#' runGist(3239667)
#' runGist("https://gist.github.com/jcheng5/3239667")
#'
#' # Old URL format without username
#' runGist("https://gist.github.com/3239667")
#' }
#'
#' @export
runGist <- function(gist,
port=NULL,
launch.browser=getOption('shiny.launch.browser',
interactive())) {
gistUrl <- if (is.numeric(gist) || grepl('^[0-9a-f]+$', gist)) {
sprintf('https://gist.github.com/%s/download', gist)
} else if(grepl('^https://gist.github.com/([^/]+/)?([0-9a-f]+)$', gist)) {
paste(gist, '/download', sep='')
} else {
stop('Unrecognized gist identifier format')
}
runUrl(gistUrl, filetype=".tar.gz", subdir=NULL, port=port,
launch.browser=launch.browser)
}
#' Run a Shiny application from a GitHub repository
#'
#' Download and launch a Shiny application that is hosted in a GitHub repository.
#'
#' @param repo Name of the repository
#' @param username GitHub username
#' @param ref Desired git reference. Could be a commit, tag, or branch
#' name. Defaults to \code{"master"}.
#' @param subdir A subdirectory in the repository that contains the app. By
#' default, this function will run an app from the top level of the repo, but
#' you can use a path such as `\code{"inst/shinyapp"}.
#' @param port The TCP port that the application should listen on. Defaults to
#' choosing a random port.
#' @param launch.browser If true, the system's default web browser will be
#' launched automatically after the app is started. Defaults to true in
#' interactive sessions only.
#'
#' @examples
#' \dontrun{
#' runGitHub("shiny_example", "rstudio")
#'
#' # Can run an app from a subdirectory in the repo
#' runGitHub("shiny_example", "rstudio", subdir = "inst/shinyapp/")
#' }
#'
#' @export
runGitHub <- function(repo, username = getOption("github.user"),
ref = "master", subdir = NULL, port = NULL,
launch.browser = getOption('shiny.launch.browser', interactive())) {
if (is.null(ref)) {
stop("Must specify either a ref. ")
}
message("Downloading github repo(s) ",
paste(repo, ref, sep = "/", collapse = ", "),
" from ",
paste(username, collapse = ", "))
name <- paste(username, "-", repo, sep = "")
url <- paste("https://github.com/", username, "/", repo, "/archive/",
ref, ".tar.gz", sep = "")
runUrl(url, subdir=subdir, port=port, launch.browser=launch.browser)
}
#' Run a Shiny application from a URL
#'
#' Download and launch a Shiny application that is hosted at a downloadable
#' URL. The Shiny application must be saved in a .zip, .tar, or .tar.gz file.
#' The Shiny application files must be contained in a subdirectory in the
#' archive. For example, the files might be \code{myapp/server.r} and
#' \code{myapp/ui.r}.
#'
#' \code{runUrl()} downloads and launches a Shiny application that is hosted at
#' a downloadable URL. The Shiny application must be saved in a .zip, .tar, or
#' .tar.gz file. The Shiny application files must be contained in the root
#' directory or a subdirectory in the archive. For example, the files might be
#' \code{myapp/server.r} and \code{myapp/ui.r}. The functions \code{runGitHub()}
#' and \code{runGist()} are based on \code{runUrl()}, using URL's from GitHub
#' (\url{https://github.com}) and GitHub gists (\url{https://gist.github.com}),
#' respectively.
#' @param url URL of the application.
#' @param filetype The file type (\code{".zip"}, \code{".tar"}, or
#' \code{".tar.gz"}. Defaults to the file extension taken from the url.
#' @param subdir A subdirectory in the repository that contains the app. By
#' default, this function will run an app from the top level of the repo, but
#' you can use a path such as `\code{"inst/shinyapp"}.
#' @param port The TCP port that the application should listen on. Defaults to
#' choosing a random port.
#' @param launch.browser If true, the system's default web browser will be
#' launched automatically after the app is started. Defaults to true in
#' interactive sessions only.
#'
#' @examples
#' \dontrun{
#' runUrl('https://github.com/rstudio/shiny_example/archive/master.tar.gz')
#'
#' # Can run an app from a subdirectory in the archive
#' runUrl("https://github.com/rstudio/shiny_example/archive/master.zip",
#' subdir = "inst/shinyapp/")
#' }
#'
#' @param destdir Directory to store the downloaded application files. If \code{NULL}
#' (the default), the application files will be stored in a temporary directory
#' and removed when the app exits
#' @param ... Other arguments to be passed to \code{\link{runApp}()}, such as
#' \code{port} and \code{launch.browser}.
#' @export
runUrl <- function(url, filetype = NULL, subdir = NULL, port = NULL,
launch.browser = getOption('shiny.launch.browser', interactive())) {
#' @examples
#' ## Only run this example in interactive R sessions
#' if (interactive()) {
#' runUrl('https://github.com/rstudio/shiny_example/archive/master.tar.gz')
#'
#' # Can run an app from a subdirectory in the archive
#' runUrl("https://github.com/rstudio/shiny_example/archive/master.zip",
#' subdir = "inst/shinyapp/")
#' }
runUrl <- function(url, filetype = NULL, subdir = NULL, destdir = NULL, ...) {
if (!is.null(subdir) && ".." %in% strsplit(subdir, '/')[[1]])
stop("'..' not allowed in subdir")
@@ -136,7 +47,15 @@ runUrl <- function(url, filetype = NULL, subdir = NULL, port = NULL,
stop("Unknown file extension.")
message("Downloading ", url)
filePath <- tempfile('shinyapp', fileext=fileext)
if (is.null(destdir)) {
filePath <- tempfile('shinyapp', fileext = fileext)
fileDir <- tempfile('shinyapp')
} else {
fileDir <- destdir
filePath <- paste(destdir, fileext)
}
dir.create(fileDir, showWarnings = FALSE)
if (download(url, filePath, mode = "wb", quiet = TRUE) != 0)
stop("Failed to download URL ", url)
on.exit(unlink(filePath))
@@ -148,17 +67,83 @@ runUrl <- function(url, filetype = NULL, subdir = NULL, port = NULL,
# 2) If the internal untar implementation is used, it chokes on the 'g'
# type flag that github uses (to stash their commit hash info).
# By using our own forked/modified untar2 we sidestep both issues.
dirname <- untar2(filePath, list=TRUE)[1]
untar2(filePath, exdir = dirname(filePath))
first <- untar2(filePath, list=TRUE)[1]
untar2(filePath, exdir = fileDir)
} else if (fileext == ".zip") {
dirname <- as.character(unzip(filePath, list=TRUE)$Name[1])
unzip(filePath, exdir = dirname(filePath))
first <- as.character(utils::unzip(filePath, list=TRUE)$Name)[1]
utils::unzip(filePath, exdir = fileDir)
}
appdir <- file.path(dirname(filePath), dirname)
on.exit(unlink(appdir, recursive = TRUE), add = TRUE)
if(is.null(destdir)){
on.exit(unlink(fileDir, recursive = TRUE), add = TRUE)
}
appsubdir <- ifelse(is.null(subdir), appdir, file.path(appdir, subdir))
runApp(appsubdir, port=port, launch.browser=launch.browser)
appdir <- file.path(fileDir, first)
if (!utils::file_test('-d', appdir)) appdir <- dirname(appdir)
if (!is.null(subdir)) appdir <- file.path(appdir, subdir)
runApp(appdir, ...)
}
#' @rdname runUrl
#' @param gist The identifier of the gist. For example, if the gist is
#' https://gist.github.com/jcheng5/3239667, then \code{3239667},
#' \code{'3239667'}, and \code{'https://gist.github.com/jcheng5/3239667'} are
#' all valid values.
#' @export
#' @examples
#' ## Only run this example in interactive R sessions
#' if (interactive()) {
#' runGist(3239667)
#' runGist("https://gist.github.com/jcheng5/3239667")
#'
#' # Old URL format without username
#' runGist("https://gist.github.com/3239667")
#' }
#'
runGist <- function(gist, destdir = NULL, ...) {
gistUrl <- if (is.numeric(gist) || grepl('^[0-9a-f]+$', gist)) {
sprintf('https://gist.github.com/%s/download', gist)
} else if(grepl('^https://gist.github.com/([^/]+/)?([0-9a-f]+)$', gist)) {
paste(gist, '/download', sep='')
} else {
stop('Unrecognized gist identifier format')
}
runUrl(gistUrl, filetype = ".zip", destdir = destdir, ...)
}
#' @rdname runUrl
#' @param repo Name of the repository.
#' @param username GitHub username. If \code{repo} is of the form
#' \code{"username/repo"}, \code{username} will be taken from \code{repo}.
#' @param ref Desired git reference. Could be a commit, tag, or branch name.
#' Defaults to \code{"master"}.
#' @export
#' @examples
#' ## Only run this example in interactive R sessions
#' if (interactive()) {
#' runGitHub("shiny_example", "rstudio")
#' # or runGitHub("rstudio/shiny_example")
#'
#' # Can run an app from a subdirectory in the repo
#' runGitHub("shiny_example", "rstudio", subdir = "inst/shinyapp/")
#' }
runGitHub <- function(repo, username = getOption("github.user"),
ref = "master", subdir = NULL, destdir = NULL, ...) {
if (grepl('/', repo)) {
res <- strsplit(repo, '/')[[1]]
if (length(res) != 2) stop("'repo' must be of the form 'username/repo'")
username <- res[1]
repo <- res[2]
}
url <- paste("https://github.com/", username, "/", repo, "/archive/",
ref, ".tar.gz", sep = "")
runUrl(url, subdir = subdir, destdir = destdir, ...)
}

111
R/server-input-handlers.R Normal file
View File

@@ -0,0 +1,111 @@
# Create a map for input handlers and register the defaults.
inputHandlers <- Map$new()
#' Register an Input Handler
#'
#' Adds an input handler for data of this type. When called, Shiny will use the
#' function provided to refine the data passed back from the client (after being
#' deserialized by jsonlite) before making it available in the \code{input}
#' variable of the \code{server.R} file.
#'
#' This function will register the handler for the duration of the R process
#' (unless Shiny is explicitly reloaded). For that reason, the \code{type} used
#' should be very specific to this package to minimize the risk of colliding
#' with another Shiny package which might use this data type name. We recommend
#' the format of "packageName.widgetName".
#'
#' Currently Shiny registers the following handlers: \code{shiny.matrix},
#' \code{shiny.number}, and \code{shiny.date}.
#'
#' The \code{type} of a custom Shiny Input widget will be deduced using the
#' \code{getType()} JavaScript function on the registered Shiny inputBinding.
#' @param type The type for which the handler should be added -- should be a
#' single-element character vector.
#' @param fun The handler function. This is the function that will be used to
#' parse the data delivered from the client before it is available in the
#' \code{input} variable. The function will be called with the following three
#' parameters:
#' \enumerate{
#' \item{The value of this input as provided by the client, deserialized
#' using jsonlite.}
#' \item{The \code{shinysession} in which the input exists.}
#' \item{The name of the input.}
#' }
#' @param force If \code{TRUE}, will overwrite any existing handler without
#' warning. If \code{FALSE}, will throw an error if this class already has
#' a handler defined.
#' @examples
#' \dontrun{
#' # Register an input handler which rounds a input number to the nearest integer
#' registerInputHandler("mypackage.validint", function(x, shinysession, name) {
#' if (is.null(x)) return(NA)
#' round(x)
#' })
#'
#' ## On the Javascript side, the associated input binding must have a corresponding getType method:
#' getType: function(el) {
#' return "mypackage.validint";
#' }
#'
#' }
#' @seealso \code{\link{removeInputHandler}}
#' @export
registerInputHandler <- function(type, fun, force=FALSE){
if (inputHandlers$containsKey(type) && !force){
stop("There is already an input handler for type: ", type)
}
inputHandlers$set(type, fun)
}
#' Deregister an Input Handler
#'
#' Removes an Input Handler. Rather than using the previously specified handler
#' for data of this type, the default jsonlite serialization will be used.
#'
#' @param type The type for which handlers should be removed.
#' @return The handler previously associated with this \code{type}, if one
#' existed. Otherwise, \code{NULL}.
#' @seealso \code{\link{registerInputHandler}}
#' @export
removeInputHandler <- function(type){
inputHandlers$remove(type)
}
# Takes a list-of-lists and returns a matrix. The lists
# must all be the same length. NULL is replaced by NA.
registerInputHandler("shiny.matrix", function(data, ...) {
if (length(data) == 0)
return(matrix(nrow=0, ncol=0))
m <- matrix(unlist(lapply(data, function(x) {
sapply(x, function(y) {
ifelse(is.null(y), NA, y)
})
})), nrow = length(data[[1]]), ncol = length(data))
return(m)
})
registerInputHandler("shiny.number", function(val, ...){
ifelse(is.null(val), NA, val)
})
registerInputHandler("shiny.date", function(val, ...){
# First replace NULLs with NA, then convert to Date vector
datelist <- ifelse(lapply(val, is.null), NA, val)
as.Date(unlist(datelist))
})
registerInputHandler("shiny.datetime", function(val, ...){
# First replace NULLs with NA, then convert to POSIXct vector
times <- lapply(val, function(x) {
if (is.null(x)) NA
else x
})
as.POSIXct(unlist(times), origin = "1970-01-01", tz = "UTC")
})
registerInputHandler("shiny.action", function(val, ...) {
# mark up the action button value with a special class so we can recognize it later
class(val) <- c(class(val), "shinyActionButtonValue")
val
})

935
R/server.R Normal file
View File

@@ -0,0 +1,935 @@
#' @include server-input-handlers.R
appsByToken <- Map$new()
# Provide a character representation of the WS that can be used
# as a key in a Map.
wsToKey <- function(WS) {
as.character(WS$socket)
}
.globals$clients <- function(req) NULL
clearClients <- function() {
.globals$clients <- function(req) NULL
}
registerClient <- function(client) {
.globals$clients <- append(.globals$clients, client)
}
.globals$resources <- list()
.globals$showcaseDefault <- 0
.globals$showcaseOverride <- FALSE
#' Resource Publishing
#'
#' Adds a directory of static resources to Shiny's web server, with the given
#' path prefix. Primarily intended for package authors to make supporting
#' JavaScript/CSS files available to their components.
#'
#' @param prefix The URL prefix (without slashes). Valid characters are a-z,
#' A-Z, 0-9, hyphen, period, and underscore; and must begin with a-z or A-Z.
#' For example, a value of 'foo' means that any request paths that begin with
#' '/foo' will be mapped to the given directory.
#' @param directoryPath The directory that contains the static resources to be
#' served.
#'
#' @details You can call \code{addResourcePath} multiple times for a given
#' \code{prefix}; only the most recent value will be retained. If the
#' normalized \code{directoryPath} is different than the directory that's
#' currently mapped to the \code{prefix}, a warning will be issued.
#'
#' @seealso \code{\link{singleton}}
#'
#' @examples
#' addResourcePath('datasets', system.file('data', package='datasets'))
#'
#' @export
addResourcePath <- function(prefix, directoryPath) {
prefix <- prefix[1]
if (!grepl('^[a-z][a-z0-9\\-_.]*$', prefix, ignore.case=TRUE, perl=TRUE)) {
stop("addResourcePath called with invalid prefix; please see documentation")
}
if (prefix %in% c('shared')) {
stop("addResourcePath called with the reserved prefix '", prefix, "'; ",
"please use a different prefix")
}
directoryPath <- normalizePath(directoryPath, mustWork=TRUE)
existing <- .globals$resources[[prefix]]
.globals$resources[[prefix]] <- list(directoryPath=directoryPath,
func=staticHandler(directoryPath))
}
resourcePathHandler <- function(req) {
if (!identical(req$REQUEST_METHOD, 'GET'))
return(NULL)
path <- req$PATH_INFO
match <- regexpr('^/([^/]+)/', path, perl=TRUE)
if (match == -1)
return(NULL)
len <- attr(match, 'capture.length')
prefix <- substr(path, 2, 2 + len - 1)
resInfo <- .globals$resources[[prefix]]
if (is.null(resInfo))
return(NULL)
suffix <- substr(path, 2 + len, nchar(path))
subreq <- as.environment(as.list(req, all.names=TRUE))
subreq$PATH_INFO <- suffix
subreq$SCRIPT_NAME <- paste(subreq$SCRIPT_NAME, substr(path, 1, 2 + len), sep='')
return(resInfo$func(subreq))
}
#' Define Server Functionality
#'
#' Defines the server-side logic of the Shiny application. This generally
#' involves creating functions that map user inputs to various kinds of output.
#' In older versions of Shiny, it was necessary to call \code{shinyServer()} in
#' the \code{server.R} file, but this is no longer required as of Shiny 0.10.
#' Now the \code{server.R} file may simply return the appropriate server
#' function (as the last expression in the code), without calling
#' \code{shinyServer()}.
#'
#' Call \code{shinyServer} from your application's \code{server.R}
#' file, passing in a "server function" that provides the server-side logic of
#' your application.
#'
#' The server function will be called when each client (web browser) first loads
#' the Shiny application's page. It must take an \code{input} and an
#' \code{output} parameter. Any return value will be ignored. It also takes an
#' optional \code{session} parameter, which is used when greater control is
#' needed.
#'
#' See the \href{http://rstudio.github.com/shiny/tutorial/}{tutorial} for more
#' on how to write a server function.
#'
#' @param func The server function for this application. See the details section
#' for more information.
#'
#' @examples
#' \dontrun{
#' # A very simple Shiny app that takes a message from the user
#' # and outputs an uppercase version of it.
#' shinyServer(function(input, output, session) {
#' output$uppercase <- renderText({
#' toupper(input$message)
#' })
#' })
#'
#'
#' # It is also possible for a server.R file to simply return the function,
#' # without calling shinyServer().
#' # For example, the server.R file could contain just the following:
#' function(input, output, session) {
#' output$uppercase <- renderText({
#' toupper(input$message)
#' })
#' }
#' }
#'
#' @export
shinyServer <- function(func) {
.globals$server <- list(func)
invisible(func)
}
decodeMessage <- function(data) {
readInt <- function(pos) {
packBits(rawToBits(data[pos:(pos+3)]), type='integer')
}
if (readInt(1) != 0x01020202L) {
# Treat message as UTF-8
charData <- rawToChar(data)
Encoding(charData) <- 'UTF-8'
return(jsonlite::fromJSON(charData, simplifyVector=FALSE))
}
i <- 5
parts <- list()
while (i <= length(data)) {
length <- readInt(i)
i <- i + 4
if (length != 0)
parts <- append(parts, list(data[i:(i+length-1)]))
else
parts <- append(parts, list(raw(0)))
i <- i + length
}
mainMessage <- decodeMessage(parts[[1]])
mainMessage$blobs <- parts[2:length(parts)]
return(mainMessage)
}
createAppHandlers <- function(httpHandlers, serverFuncSource) {
appvars <- new.env()
appvars$server <- NULL
sys.www.root <- system.file('www', package='shiny')
# This value, if non-NULL, must be present on all HTTP and WebSocket
# requests as the Shiny-Shared-Secret header or else access will be
# denied (403 response for HTTP, and instant close for websocket).
sharedSecret <- getOption('shiny.sharedSecret')
appHandlers <- list(
http = joinHandlers(c(
sessionHandler,
httpHandlers,
sys.www.root,
resourcePathHandler,
reactLogHandler)),
ws = function(ws) {
if (!is.null(sharedSecret)
&& !identical(sharedSecret, ws$request$HTTP_SHINY_SHARED_SECRET)) {
ws$close()
return(TRUE)
}
if (!is.null(getOption("shiny.observer.error", NULL))) {
warning(
call. = FALSE,
"options(shiny.observer.error) is no longer supported; please unset it!"
)
stopApp()
}
shinysession <- ShinySession$new(ws)
appsByToken$set(shinysession$token, shinysession)
shinysession$setShowcase(.globals$showcaseDefault)
messageHandler <- function(binary, msg) {
withReactiveDomain(shinysession, {
# To ease transition from websockets-based code. Should remove once we're stable.
if (is.character(msg))
msg <- charToRaw(msg)
if (isTRUE(getOption('shiny.trace'))) {
if (binary)
message("RECV ", '$$binary data$$')
else
message("RECV ", rawToChar(msg))
}
if (identical(charToRaw("\003\xe9"), msg))
return()
msg <- decodeMessage(msg)
# Do our own list simplifying here. sapply/simplify2array give names to
# character vectors, which is rarely what we want.
if (!is.null(msg$data)) {
for (name in names(msg$data)) {
val <- msg$data[[name]]
splitName <- strsplit(name, ':')[[1]]
if (length(splitName) > 1) {
msg$data[[name]] <- NULL
if (!inputHandlers$containsKey(splitName[[2]])){
# No input handler registered for this type
stop("No handler registered for for type ", name)
}
msg$data[[ splitName[[1]] ]] <-
inputHandlers$get(splitName[[2]])(
val,
shinysession,
splitName[[1]] )
}
else if (is.list(val) && is.null(names(val))) {
val_flat <- unlist(val, recursive = TRUE)
if (is.null(val_flat)) {
# This is to assign NULL instead of deleting the item
msg$data[name] <- list(NULL)
} else {
msg$data[[name]] <- val_flat
}
}
}
}
switch(
msg$method,
init = {
serverFunc <- withReactiveDomain(NULL, serverFuncSource())
if (!identicalFunctionBodies(serverFunc, appvars$server)) {
appvars$server <- serverFunc
if (!is.null(appvars$server))
{
# Tag this function as the Shiny server function. A debugger may use this
# tag to give this function special treatment.
# It's very important that it's appvars$server itself and NOT a copy that
# is invoked, otherwise new breakpoints won't be picked up.
attr(appvars$server, "shinyServerFunction") <- TRUE
registerDebugHook("server", appvars, "Server Function")
}
}
# Check for switching into/out of showcase mode
if (.globals$showcaseOverride &&
exists(".clientdata_url_search", where = msg$data)) {
mode <- showcaseModeOfQuerystring(msg$data$.clientdata_url_search)
if (!is.null(mode))
shinysession$setShowcase(mode)
}
shinysession$manageInputs(msg$data)
# The client tells us what singletons were rendered into
# the initial page
if (!is.null(msg$data$.clientdata_singletons)) {
shinysession$singletons <- strsplit(
msg$data$.clientdata_singletons, ',')[[1]]
}
local({
args <- argsForServerFunc(serverFunc, shinysession)
withReactiveDomain(shinysession, {
do.call(
# No corresponding ..stacktraceoff; the server func is pure
# user code
wrapFunctionLabel(appvars$server, "server",
..stacktraceon = TRUE
),
args
)
})
})
},
update = {
shinysession$manageInputs(msg$data)
},
shinysession$dispatch(msg)
)
shinysession$manageHiddenOutputs()
if (exists(".shiny__stdout", globalenv()) &&
exists("HTTP_GUID", ws$request)) {
# safe to assume we're in shiny-server
shiny_stdout <- get(".shiny__stdout", globalenv())
# eNter a flushReact
writeLines(paste("_n_flushReact ", get("HTTP_GUID", ws$request),
" @ ", sprintf("%.3f", as.numeric(Sys.time())),
sep=""), con=shiny_stdout)
flush(shiny_stdout)
flushReact()
# eXit a flushReact
writeLines(paste("_x_flushReact ", get("HTTP_GUID", ws$request),
" @ ", sprintf("%.3f", as.numeric(Sys.time())),
sep=""), con=shiny_stdout)
flush(shiny_stdout)
} else {
flushReact()
}
lapply(appsByToken$values(), function(shinysession) {
shinysession$flushOutput()
NULL
})
})
}
ws$onMessage(function(binary, msg) {
# If unhandled errors occur, make sure they get properly logged
withLogErrors(messageHandler(binary, msg))
})
ws$onClose(function() {
shinysession$wsClosed()
appsByToken$remove(shinysession$token)
})
return(TRUE)
}
)
return(appHandlers)
}
# Determine what arguments should be passed to this serverFunc. All server funcs
# must take input and output, but clientData (obsolete) and session are
# optional.
argsForServerFunc <- function(serverFunc, session) {
args <- list(input = session$input, output = .createOutputWriter(session))
paramNames <- names(formals(serverFunc))
# The clientData and session arguments are optional; check if
# each exists
if ("clientData" %in% paramNames)
args$clientData <- session$clientData
if ("session" %in% paramNames)
args$session <- session
args
}
getEffectiveBody <- function(func) {
# Note: NULL values are OK. isS4(NULL) returns FALSE, body(NULL)
# returns NULL.
if (isS4(func) && class(func) == "functionWithTrace")
body(func@original)
else
body(func)
}
identicalFunctionBodies <- function(a, b) {
identical(getEffectiveBody(a), getEffectiveBody(b))
}
handlerManager <- HandlerManager$new()
addSubApp <- function(appObj, autoRemove = TRUE) {
path <- createUniqueId(16, "/app")
appHandlers <- createAppHandlers(appObj$httpHandler, appObj$serverFuncSource)
# remove the leading / from the path so a relative path is returned
# (needed for the case where the root URL for the Shiny app isn't /, such
# as portmapped URLs)
finalPath <- paste(
substr(path, 2, nchar(path)),
"/?w=", workerId(),
"&__subapp__=1",
sep="")
handlerManager$addHandler(routeHandler(path, appHandlers$http), finalPath)
handlerManager$addWSHandler(routeWSHandler(path, appHandlers$ws), finalPath)
if (autoRemove) {
# If a session is currently active, remove this subapp automatically when
# the current session ends
onReactiveDomainEnded(getDefaultReactiveDomain(), function() {
removeSubApp(finalPath)
})
}
return(finalPath)
}
removeSubApp <- function(path) {
handlerManager$removeHandler(path)
handlerManager$removeWSHandler(path)
}
startApp <- function(appObj, port, host, quiet) {
appHandlers <- createAppHandlers(appObj$httpHandler, appObj$serverFuncSource)
handlerManager$addHandler(appHandlers$http, "/", tail = TRUE)
handlerManager$addWSHandler(appHandlers$ws, "/", tail = TRUE)
if (is.numeric(port) || is.integer(port)) {
if (!quiet) {
message('\n', 'Listening on http://', host, ':', port)
}
return(startServer(host, port, handlerManager$createHttpuvApp()))
} else if (is.character(port)) {
if (!quiet) {
message('\n', 'Listening on domain socket ', port)
}
mask <- attr(port, 'mask')
return(startPipeServer(port, mask, handlerManager$createHttpuvApp()))
}
}
# Run an application that was created by \code{\link{startApp}}. This
# function should normally be called in a \code{while(TRUE)} loop.
serviceApp <- function() {
if (timerCallbacks$executeElapsed()) {
for (shinysession in appsByToken$values()) {
shinysession$manageHiddenOutputs()
}
flushReact()
for (shinysession in appsByToken$values()) {
shinysession$flushOutput()
}
}
# If this R session is interactive, then call service() with a short timeout
# to keep the session responsive to user input
maxTimeout <- ifelse(interactive(), 100, 1000)
timeout <- max(1, min(maxTimeout, timerCallbacks$timeToNextEvent()))
service(timeout)
}
.shinyServerMinVersion <- '0.3.4'
#' Run Shiny Application
#'
#' Runs a Shiny application. This function normally does not return; interrupt R
#' to stop the application (usually by pressing Ctrl+C or Esc).
#'
#' The host parameter was introduced in Shiny 0.9.0. Its default value of
#' \code{"127.0.0.1"} means that, contrary to previous versions of Shiny, only
#' the current machine can access locally hosted Shiny apps. To allow other
#' clients to connect, use the value \code{"0.0.0.0"} instead (which was the
#' value that was hard-coded into Shiny in 0.8.0 and earlier).
#'
#' @param appDir The application to run. Should be one of the following:
#' \itemize{
#' \item A directory containing \code{server.R}, plus, either \code{ui.R} or
#' a \code{www} directory that contains the file \code{index.html}.
#' \item A directory containing \code{app.R}.
#' \item An \code{.R} file containing a Shiny application, ending with an
#' expression that produces a Shiny app object.
#' \item A list with \code{ui} and \code{server} components.
#' \item A Shiny app object created by \code{\link{shinyApp}}.
#' }
#' @param port The TCP port that the application should listen on. If the
#' \code{port} is not specified, and the \code{shiny.port} option is set (with
#' \code{options(shiny.port = XX)}), then that port will be used. Otherwise,
#' use a random port.
#' @param launch.browser If true, the system's default web browser will be
#' launched automatically after the app is started. Defaults to true in
#' interactive sessions only. This value of this parameter can also be a
#' function to call with the application's URL.
#' @param host The IPv4 address that the application should listen on. Defaults
#' to the \code{shiny.host} option, if set, or \code{"127.0.0.1"} if not. See
#' Details.
#' @param workerId Can generally be ignored. Exists to help some editions of
#' Shiny Server Pro route requests to the correct process.
#' @param quiet Should Shiny status messages be shown? Defaults to FALSE.
#' @param display.mode The mode in which to display the application. If set to
#' the value \code{"showcase"}, shows application code and metadata from a
#' \code{DESCRIPTION} file in the application directory alongside the
#' application. If set to \code{"normal"}, displays the application normally.
#' Defaults to \code{"auto"}, which displays the application in the mode given
#' in its \code{DESCRIPTION} file, if any.
#'
#' @examples
#' \dontrun{
#' # Start app in the current working directory
#' runApp()
#'
#' # Start app in a subdirectory called myapp
#' runApp("myapp")
#' }
#'
#' ## Only run this example in interactive R sessions
#' if (interactive()) {
#' # Apps can be run without a server.r and ui.r file
#' runApp(list(
#' ui = bootstrapPage(
#' numericInput('n', 'Number of obs', 100),
#' plotOutput('plot')
#' ),
#' server = function(input, output) {
#' output$plot <- renderPlot({ hist(runif(input$n)) })
#' }
#' ))
#'
#'
#' # Running a Shiny app object
#' app <- shinyApp(
#' ui = bootstrapPage(
#' numericInput('n', 'Number of obs', 100),
#' plotOutput('plot')
#' ),
#' server = function(input, output) {
#' output$plot <- renderPlot({ hist(runif(input$n)) })
#' }
#' )
#' runApp(app)
#' }
#' @export
runApp <- function(appDir=getwd(),
port=getOption('shiny.port'),
launch.browser=getOption('shiny.launch.browser',
interactive()),
host=getOption('shiny.host', '127.0.0.1'),
workerId="", quiet=FALSE,
display.mode=c("auto", "normal", "showcase")) {
on.exit({
handlerManager$clear()
}, add = TRUE)
if (is.null(host) || is.na(host))
host <- '0.0.0.0'
# Make warnings print immediately
ops <- options(warn = 1)
on.exit(options(ops), add = TRUE)
workerId(workerId)
if (nzchar(Sys.getenv('SHINY_PORT'))) {
# If SHINY_PORT is set, we're running under Shiny Server. Check the version
# to make sure it is compatible. Older versions of Shiny Server don't set
# SHINY_SERVER_VERSION, those will return "" which is considered less than
# any valid version.
ver <- Sys.getenv('SHINY_SERVER_VERSION')
if (utils::compareVersion(ver, .shinyServerMinVersion) < 0) {
warning('Shiny Server v', .shinyServerMinVersion,
' or later is required; please upgrade!')
}
}
# Showcase mode is disabled by default; it must be explicitly enabled in
# either the DESCRIPTION file for directory-based apps, or via
# the display.mode parameter. The latter takes precedence.
setShowcaseDefault(0)
# If appDir specifies a path, and display mode is specified in the
# DESCRIPTION file at that path, apply it here.
if (is.character(appDir)) {
# if appDir specifies a .R file (single-file Shiny app), look for the
# DESCRIPTION in the parent directory
desc <- file.path.ci(
if (tolower(tools::file_ext(appDir)) == "r")
dirname(appDir)
else
appDir, "DESCRIPTION")
if (file.exists(desc)) {
con <- file(desc, encoding = checkEncoding(desc))
on.exit(close(con), add = TRUE)
settings <- read.dcf(con)
if ("DisplayMode" %in% colnames(settings)) {
mode <- settings[1,"DisplayMode"]
if (mode == "Showcase") {
setShowcaseDefault(1)
}
}
}
}
# If display mode is specified as an argument, apply it (overriding the
# value specified in DESCRIPTION, if any).
display.mode <- match.arg(display.mode)
if (display.mode == "normal")
setShowcaseDefault(0)
else if (display.mode == "showcase")
setShowcaseDefault(1)
require(shiny)
# determine port if we need to
if (is.null(port)) {
# Try up to 20 random ports. If we don't succeed just plow ahead
# with the final value we tried, and let the "real" startServer
# somewhere down the line fail and throw the error to the user.
#
# If we (think we) succeed, save the value as .globals$lastPort,
# and try that first next time the user wants a random port.
for (i in 1:20) {
if (!is.null(.globals$lastPort)) {
port <- .globals$lastPort
.globals$lastPort <- NULL
}
else {
# Try up to 20 random ports
port <- p_randomInt(3000, 8000)
}
# Test port to see if we can use it
tmp <- try(startServer(host, port, list()), silent=TRUE)
if (!inherits(tmp, 'try-error')) {
stopServer(tmp)
.globals$lastPort <- port
break
}
}
}
appParts <- as.shiny.appobj(appDir)
# Set up the onEnd before we call onStart, so that it gets called even if an
# error happens in onStart.
if (!is.null(appParts$onEnd))
on.exit(appParts$onEnd(), add = TRUE)
if (!is.null(appParts$onStart))
appParts$onStart()
server <- startApp(appParts, port, host, quiet)
on.exit({
stopServer(server)
}, add = TRUE)
if (!is.character(port)) {
# http://0.0.0.0/ doesn't work on QtWebKit (i.e. RStudio viewer)
browseHost <- if (identical(host, "0.0.0.0")) "127.0.0.1" else host
appUrl <- paste("http://", browseHost, ":", port, sep="")
if (is.function(launch.browser))
launch.browser(appUrl)
else if (launch.browser)
utils::browseURL(appUrl)
} else {
appUrl <- NULL
}
# call application hooks
callAppHook("onAppStart", appUrl)
on.exit({
callAppHook("onAppStop", appUrl)
}, add = TRUE)
.globals$reterror <- NULL
.globals$retval <- NULL
.globals$stopped <- FALSE
# Top-level ..stacktraceoff..; matches with ..stacktraceon in observe(),
# reactive(), Callbacks$invoke(), and others
..stacktraceoff..(
captureStackTraces(
while (!.globals$stopped) {
serviceApp()
Sys.sleep(0.001)
}
)
)
if (isTRUE(.globals$reterror)) {
stop(.globals$retval)
}
else if (.globals$retval$visible)
.globals$retval$value
else
invisible(.globals$retval$value)
}
#' Stop the currently running Shiny app
#'
#' Stops the currently running Shiny app, returning control to the caller of
#' \code{\link{runApp}}.
#'
#' @param returnValue The value that should be returned from
#' \code{\link{runApp}}.
#'
#' @export
stopApp <- function(returnValue = invisible()) {
# reterror will indicate whether retval is an error (i.e. it should be passed
# to stop() when the serviceApp loop stops) or a regular value (in which case
# it should simply be returned with the appropriate visibility).
.globals$reterror <- FALSE
..stacktraceoff..(
tryCatch(
{
captureStackTraces(
.globals$retval <- withVisible(..stacktraceon..(force(returnValue)))
)
},
error = function(e) {
.globals$retval <- e
.globals$reterror <- TRUE
}
)
)
.globals$stopped <- TRUE
httpuv::interrupt()
}
#' Run Shiny Example Applications
#'
#' Launch Shiny example applications, and optionally, your system's web browser.
#'
#' @param example The name of the example to run, or \code{NA} (the default) to
#' list the available examples.
#' @param port The TCP port that the application should listen on. Defaults to
#' choosing a random port.
#' @param launch.browser If true, the system's default web browser will be
#' launched automatically after the app is started. Defaults to true in
#' interactive sessions only.
#' @param host The IPv4 address that the application should listen on. Defaults
#' to the \code{shiny.host} option, if set, or \code{"127.0.0.1"} if not.
#' @param display.mode The mode in which to display the example. Defaults to
#' \code{showcase}, but may be set to \code{normal} to see the example without
#' code or commentary.
#'
#' @examples
#' ## Only run this example in interactive R sessions
#' if (interactive()) {
#' # List all available examples
#' runExample()
#'
#' # Run one of the examples
#' runExample("01_hello")
#'
#' # Print the directory containing the code for all examples
#' system.file("examples", package="shiny")
#' }
#' @export
runExample <- function(example=NA,
port=NULL,
launch.browser=getOption('shiny.launch.browser',
interactive()),
host=getOption('shiny.host', '127.0.0.1'),
display.mode=c("auto", "normal", "showcase")) {
examplesDir <- system.file('examples', package='shiny')
dir <- resolve(examplesDir, example)
if (is.null(dir)) {
if (is.na(example)) {
errFun <- message
errMsg <- ''
}
else {
errFun <- stop
errMsg <- paste('Example', example, 'does not exist. ')
}
errFun(errMsg,
'Valid examples are "',
paste(list.files(examplesDir), collapse='", "'),
'"')
}
else {
runApp(dir, port = port, host = host, launch.browser = launch.browser,
display.mode = display.mode)
}
}
#' Run a gadget
#'
#' Similar to \code{runApp}, but handles \code{input$cancel} automatically, and
#' if running in RStudio, defaults to viewing the app in the Viewer pane.
#'
#' @param app Either a Shiny app object as created by
#' \code{\link[=shiny]{shinyApp}} et al, or, a UI object.
#' @param server Ignored if \code{app} is a Shiny app object; otherwise, passed
#' along to \code{shinyApp} (i.e. \code{shinyApp(ui = app, server = server)}).
#' @param port See \code{\link[=shiny]{runApp}}.
#' @param viewer Specify where the gadget should be displayed--viewer pane,
#' dialog window, or external browser--by passing in a call to one of the
#' \code{\link{viewer}} functions.
#' @param stopOnCancel If \code{TRUE} (the default), then an \code{observeEvent}
#' is automatically created that handles \code{input$cancel} by calling
#' \code{stopApp()} with an error. Pass \code{FALSE} if you want to handle
#' \code{input$cancel} yourself.
#' @return The value returned by the gadget.
#'
#' @examples
#' \dontrun{
#' library(shiny)
#'
#' ui <- fillPage(...)
#'
#' server <- function(input, output, session) {
#' ...
#' }
#'
#' # Either pass ui/server as separate arguments...
#' runGadget(ui, server)
#'
#' # ...or as a single app object
#' runGadget(shinyApp(ui, server))
#' }
#'
#' @export
runGadget <- function(app, server = NULL, port = getOption("shiny.port"),
viewer = paneViewer(), stopOnCancel = TRUE) {
if (!is.shiny.appobj(app)) {
app <- shinyApp(app, server)
}
if (isTRUE(stopOnCancel)) {
app <- decorateServerFunc(app, function(input, output, session) {
observeEvent(input$cancel, {
stopApp(stop("User cancel", call. = FALSE))
})
})
}
if (is.null(viewer)) {
viewer <- utils::browseURL
}
shiny::runApp(app, port = port, launch.browser = viewer)
}
# Add custom functionality to a Shiny app object's server func
decorateServerFunc <- function(appobj, serverFunc) {
origServerFuncSource <- appobj$serverFuncSource
appobj$serverFuncSource <- function() {
origServerFunc <- origServerFuncSource()
function(input, output, session) {
serverFunc(input, output, session)
# The clientData and session arguments are optional; check if
# each exists
args <- argsForServerFunc(origServerFunc, session)
do.call(origServerFunc, args)
}
}
appobj
}
#' Viewer options
#'
#' Use these functions to control where the gadget is displayed in RStudio (or
#' other R environments that emulate RStudio's viewer pane/dialog APIs). If
#' viewer APIs are not available in the current R environment, then the gadget
#' will be displayed in the system's default web browser (see
#' \code{\link[utils]{browseURL}}).
#'
#' @return A function that takes a single \code{url} parameter, suitable for
#' passing as the \code{viewer} argument of \code{\link{runGadget}}.
#'
#' @rdname viewer
#' @name viewer
NULL
#' @param minHeight The minimum height (in pixels) desired to show the gadget in
#' the viewer pane. If a positive number, resize the pane if necessary to show
#' at least that many pixels. If \code{NULL}, use the existing viewer pane
#' size. If \code{"maximize"}, use the maximum available vertical space.
#' @rdname viewer
#' @export
paneViewer <- function(minHeight = NULL) {
viewer <- getOption("viewer")
if (is.null(viewer)) {
utils::browseURL
} else {
function(url) {
viewer(url, minHeight)
}
}
}
#' @param dialogName The window title to display for the dialog.
#' @param width,height The desired dialog width/height, in pixels.
#' @rdname viewer
#' @export
dialogViewer <- function(dialogName, width = 600, height = 600) {
viewer <- getOption("shinygadgets.showdialog")
if (is.null(viewer)) {
utils::browseURL
} else {
function(url) {
viewer(dialogName, url, width = width, height = height)
}
}
}
#' @param browser See \code{\link[utils]{browseURL}}.
#' @rdname viewer
#' @export
browserViewer <- function(browser = getOption("browser")) {
function(url) {
utils::browseURL(url, browser = browser)
}
}

1911
R/shiny.R

File diff suppressed because it is too large Load Diff

View File

@@ -1,252 +1,111 @@
#' @include globals.R
NULL
#' @export
p <- function(...) tags$p(...)
#' @export
h1 <- function(...) tags$h1(...)
#' @export
h2 <- function(...) tags$h2(...)
#' @export
h3 <- function(...) tags$h3(...)
#' @export
h4 <- function(...) tags$h4(...)
#' @export
h5 <- function(...) tags$h5(...)
#' @export
h6 <- function(...) tags$h6(...)
#' @export
a <- function(...) tags$a(...)
#' @export
br <- function(...) tags$br(...)
#' @export
div <- function(...) tags$div(...)
#' @export
span <- function(...) tags$span(...)
#' @export
pre <- function(...) tags$pre(...)
#' @export
code <- function(...) tags$code(...)
#' @export
img <- function(...) tags$img(...)
#' @export
strong <- function(...) tags$strong(...)
#' @export
em <- function(...) tags$em(...)
#' Include Content From a File
#'
#' Include HTML, text, or rendered Markdown into a \link[=shinyUI]{Shiny UI}.
#'
#' 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.
#'
#' @note The \code{includeMarkdown} function requires the \code{markdown}
#' package.
#'
#' @param 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.
#'
#' @rdname include
#' @export
includeHTML <- function(path) {
dependsOnFile(path)
lines <- readLines(path, warn=FALSE, encoding='UTF-8')
return(HTML(paste(lines, collapse='\r\n')))
}
#' @rdname include
#' @export
includeText <- function(path) {
dependsOnFile(path)
lines <- readLines(path, warn=FALSE, encoding='UTF-8')
return(paste(lines, collapse='\r\n'))
}
#' @rdname include
#' @export
includeMarkdown <- function(path) {
if (!require(markdown))
stop("Markdown package is not installed")
dependsOnFile(path)
html <- markdown::markdownToHTML(path, fragment.only=TRUE)
Encoding(html) <- 'UTF-8'
return(HTML(html))
}
#' @param ... Any additional attributes to be applied to the generated tag.
#' @rdname include
#' @export
includeCSS <- function(path, ...) {
dependsOnFile(path)
lines <- readLines(path, warn=FALSE, encoding='UTF-8')
args <- list(...)
if (is.null(args$type))
args$type <- 'text/css'
return(do.call(tags$style,
c(list(HTML(paste(lines, collapse='\r\n'))), args)))
}
#' @rdname include
#' @export
includeScript <- function(path, ...) {
dependsOnFile(path)
lines <- readLines(path, warn=FALSE, encoding='UTF-8')
return(tags$script(HTML(paste(lines, collapse='\r\n')), ...))
}
#' Include Content Only Once
#'
#' Use \code{singleton} to wrap contents (tag, text, HTML, or lists) that should
#' be included in the generated document only once, yet may appear in the
#' document-generating code more than once. Only the first appearance of the
#' content (in document order) will be used. Useful for custom components that
#' have JavaScript files or stylesheets.
#'
#' @param x A \code{\link{tag}}, text, \code{\link{HTML}}, or list.
#' Load the MathJax library and typeset math expressions
#'
#' This function adds MathJax to the page and typeset the math expressions (if
#' found) in the content \code{...}. It only needs to be called once in an app
#' unless the content is rendered \emph{after} the page is loaded, e.g. via
#' \code{\link{renderUI}}, in which case we have to call it explicitly every
#' time we write math expressions to the output.
#' @param ... any HTML elements to apply MathJax to
#' @export
singleton <- function(x) {
class(x) <- c(class(x), 'shiny.singleton')
return(x)
#' @examples withMathJax(helpText("Some math here $$\\alpha+\\beta$$"))
#' # now we can just write "static" content without withMathJax()
#' div("more math here $$\\sqrt{2}$$")
withMathJax <- function(...) {
path <- 'https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML'
tagList(
tags$head(
singleton(tags$script(src = path, type = 'text/javascript'))
),
...,
tags$script(HTML('MathJax.Hub.Queue(["Typeset", MathJax.Hub]);'))
)
}
renderPage <- function(ui, connection) {
# provide a filter so we can intercept head tag requests
context <- new.env()
context$head <- character()
context$singletons <- character()
context$filter <- function(content) {
if (inherits(content, 'shiny.singleton')) {
sig <- digest(content, algo='sha1')
if (sig %in% context$singletons)
return(FALSE)
context$singletons <- c(sig, context$singletons)
}
if (isTag(content) && identical(content$name, "head")) {
textConn <- textConnection(NULL, "w")
textConnWriter <- function(text) cat(text, file = textConn)
tagWrite(content$children, textConnWriter, 1, context)
context$head <- append(context$head, textConnectionValue(textConn))
close(textConn)
return (FALSE)
}
else {
return (TRUE)
}
renderPage <- function(ui, connection, showcase=0) {
# If the ui is a NOT complete document (created by htmlTemplate()), then do some
# preprocessing and make sure it's a complete document.
if (!inherits(ui, "html_document")) {
if (showcase > 0)
ui <- showcaseUI(ui)
# Wrap ui in body tag if it doesn't already have a single top-level body tag.
if (!(inherits(ui, "shiny.tag") && ui$name == "body"))
ui <- tags$body(ui)
# Put the body into the default template
ui <- htmlTemplate(
system.file("template", "default.html", package = "shiny"),
body = ui
)
}
# write ui HTML to a character vector
textConn <- textConnection(NULL, "w")
tagWrite(ui, function(text) cat(text, file = textConn), 0, context)
uiHTML <- textConnectionValue(textConn)
close(textConn)
# write preamble
writeLines(c('<!DOCTYPE html>',
'<html>',
'<head>',
' <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>',
' <script src="shared/jquery.js" type="text/javascript"></script>',
' <script src="shared/shiny.js" type="text/javascript"></script>',
' <link rel="stylesheet" type="text/css" href="shared/shiny.css"/>',
context$head,
'</head>',
'<body>',
recursive=TRUE),
con = connection)
# write UI html to connection
writeLines(uiHTML, con = connection)
# write end document
writeLines(c('</body>',
'</html>'),
con = connection)
shiny_deps <- list(
htmlDependency("json2", "2014.02.04", c(href="shared"), script = "json2-min.js"),
htmlDependency("jquery", "1.11.3", c(href="shared"), script = "jquery.min.js"),
htmlDependency("shiny", utils::packageVersion("shiny"), c(href="shared"),
script = if (getOption("shiny.minified", TRUE)) "shiny.min.js" else "shiny.js",
stylesheet = "shiny.css")
)
html <- renderDocument(ui, shiny_deps, processDep = createWebDependency)
writeUTF8(html, con = connection)
}
#' Create a Shiny UI handler
#'
#' Register a UI handler by providing a UI definition (created with e.g.
#' \link{pageWithSidebar}) and web server path (typically "/", the default
#' value).
#'
#' @param ui A user-interace definition
#' @param path The web server path to server the UI from
#' @return Called for its side-effect of registering a UI handler
#'
#' @examples
#' el <- div(HTML("I like <u>turtles</u>"))
#' cat(as.character(el))
#'
#' @examples
#' # Define UI
#' shinyUI(pageWithSidebar(
#'
#' # Application title
#' headerPanel("Hello Shiny!"),
#'
#' # Sidebar with a slider input
#' sidebarPanel(
#' sliderInput("obs",
#' "Number of observations:",
#' min = 0,
#' max = 1000,
#' value = 500)
#' ),
#'
#' # Show a plot of the generated distribution
#' mainPanel(
#' plotOutput("distPlot")
#' )
#' ))
#'
#' Historically this function was used in ui.R files to register a user
#' interface with Shiny. It is no longer required as of Shiny 0.10; simply
#' ensure that the last expression to be returned from ui.R is a user interface.
#' This function is kept for backwards compatibility with older applications. It
#' returns the value that is passed to it.
#'
#' @param ui A user interace definition
#' @return The user interface definition, without modifications or side effects.
#'
#' @export
shinyUI <- function(ui, path='/') {
force(ui)
registerClient({
function(req) {
if (!identical(req$REQUEST_METHOD, 'GET'))
return(NULL)
if (req$PATH_INFO != path)
return(NULL)
textConn <- textConnection(NULL, "w")
on.exit(close(textConn))
renderPage(ui, textConn)
html <- paste(textConnectionValue(textConn), collapse='\n')
return(httpResponse(200, content=html))
}
})
shinyUI <- function(ui) {
.globals$ui <- list(ui)
ui
}
uiHttpHandler <- function(ui, uiPattern = "^/$") {
force(ui)
function(req) {
if (!identical(req$REQUEST_METHOD, 'GET'))
return(NULL)
if (!isTRUE(grepl(uiPattern, req$PATH_INFO)))
return(NULL)
textConn <- file(open = "w+")
on.exit(close(textConn))
showcaseMode <- .globals$showcaseDefault
if (.globals$showcaseOverride) {
mode <- showcaseModeOfReq(req)
if (!is.null(mode))
showcaseMode <- mode
}
uiValue <- if (is.function(ui)) {
if (length(formals(ui)) > 0) {
# No corresponding ..stacktraceoff.., this is pure user code
..stacktraceon..(ui(req))
} else {
# No corresponding ..stacktraceoff.., this is pure user code
..stacktraceon..(ui())
}
} else {
ui
}
if (is.null(uiValue))
return(NULL)
renderPage(uiValue, textConn, showcaseMode)
html <- paste(readLines(textConn, encoding = 'UTF-8'), collapse='\n')
return(httpResponse(200, content=enc2utf8(html)))
}
}

View File

@@ -1,138 +1,46 @@
suppressPackageStartupMessages({
library(caTools)
library(xtable)
})
globalVariables('func')
#' Plot Output
#'
#' Renders a reactive plot that is suitable for assigning to an \code{output}
#' slot.
#'
#' The corresponding HTML output tag should be \code{div} or \code{img} and have
#' the CSS class name \code{shiny-plot-output}.
#' Mark a function as a render function
#'
#' @seealso For more details on how the plots are generated, and how to control
#' the output, see \code{\link{plotPNG}}.
#' Should be called by implementers of \code{renderXXX} functions in order to
#' mark their return values as Shiny render functions, and to provide a hint to
#' Shiny regarding what UI function is most commonly used with this type of
#' render function. This can be used in R Markdown documents to create complete
#' output widgets out of just the render function.
#'
#' @param uiFunc A function that renders Shiny UI. Must take a single argument:
#' an output ID.
#' @param renderFunc A function that is suitable for assigning to a Shiny output
#' slot.
#' @return The \code{renderFunc} function, with annotations.
#'
#' @param expr An expression that generates a plot.
#' @param width The width of the rendered plot, in pixels; or \code{'auto'} to
#' use the \code{offsetWidth} of the HTML element that is bound to this plot.
#' You can also pass in a function that returns the width in pixels or
#' \code{'auto'}; in the body of the function you may reference reactive
#' values and functions.
#' @param height The height of the rendered plot, in pixels; or \code{'auto'} to
#' use the \code{offsetHeight} of the HTML element that is bound to this plot.
#' You can also pass in a function that returns the width in pixels or
#' \code{'auto'}; in the body of the function you may reference reactive
#' values and functions.
#' @param res Resolution of resulting plot, in pixels per inch. This value is
#' passed to \code{\link{png}}. Note that this affects the resolution of PNG
#' rendering in R; it won't change the actual ppi of the browser.
#' @param ... Arguments to be passed through to \code{\link[grDevices]{png}}.
#' These can be used to set the width, height, background color, etc.
#' @param env The environment in which to evaluate \code{expr}.
#' @param quoted Is \code{expr} a quoted expression (with \code{quote()})? This
#' is useful if you want to save an expression in a variable.
#' @param func A function that generates a plot (deprecated; use \code{expr}
#' instead).
#'
#' @export
renderPlot <- function(expr, width='auto', height='auto', res=72, ...,
env=parent.frame(), quoted=FALSE, func=NULL) {
if (!is.null(func)) {
shinyDeprecated(msg="renderPlot: argument 'func' is deprecated. Please use 'expr' instead.")
} else {
installExprFunction(expr, "func", env, quoted)
}
markRenderFunction <- function(uiFunc, renderFunc) {
structure(renderFunc,
class = c("shiny.render.function", "function"),
outputFunc = uiFunc)
}
args <- list(...)
if (is.function(width))
widthWrapper <- reactive({ width() })
else
widthWrapper <- NULL
useRenderFunction <- function(renderFunc, inline = FALSE) {
outputFunction <- attr(renderFunc, "outputFunc")
id <- createUniqueId(8, "out")
o <- getDefaultReactiveDomain()$output
if (!is.null(o))
o[[id]] <- renderFunc
if (is.logical(formals(outputFunction)[["inline"]])) {
outputFunction(id, inline = inline)
} else outputFunction(id)
}
if (is.function(height))
heightWrapper <- reactive({ height() })
else
heightWrapper <- NULL
return(function(shinysession, name, ...) {
if (!is.null(widthWrapper))
width <- widthWrapper()
if (!is.null(heightWrapper))
height <- heightWrapper()
# Note that these are reactive calls. A change to the width and height
# will inherently cause a reactive plot to redraw (unless width and
# height were explicitly specified).
prefix <- 'output_'
if (width == 'auto')
width <- shinysession$clientData[[paste(prefix, name, '_width', sep='')]];
if (height == 'auto')
height <- shinysession$clientData[[paste(prefix, name, '_height', sep='')]];
if (is.null(width) || is.null(height) || width <= 0 || height <= 0)
return(NULL)
# Resolution multiplier
pixelratio <- shinysession$clientData$pixelratio
if (is.null(pixelratio))
pixelratio <- 1
coordmap <- NULL
plotFunc <- function() {
# Actually perform the plotting
func()
# Now capture some graphics device info before we close it
usrCoords <- par('usr')
usrBounds <- usrCoords
if (par('xlog')) {
usrBounds[c(1,2)] <- 10 ^ usrBounds[c(1,2)]
}
if (par('ylog')) {
usrBounds[c(3,4)] <- 10 ^ usrBounds[c(3,4)]
}
coordmap <<- list(
usr = c(
left = usrCoords[1],
right = usrCoords[2],
bottom = usrCoords[3],
top = usrCoords[4]
),
# The bounds of the plot area, in DOM pixels
bounds = c(
left = grconvertX(usrBounds[1], 'user', 'nfc') * width,
right = grconvertX(usrBounds[2], 'user', 'nfc') * width,
bottom = (1-grconvertY(usrBounds[3], 'user', 'nfc')) * height,
top = (1-grconvertY(usrBounds[4], 'user', 'nfc')) * height
),
log = c(
x = par('xlog'),
y = par('ylog')
),
pixelratio = pixelratio
)
}
outfile <- do.call(plotPNG, c(plotFunc, width=width*pixelratio,
height=height*pixelratio, res=res*pixelratio, args))
on.exit(unlink(outfile))
# Return a list of attributes for the img
return(list(
src=shinysession$fileUrl(name, outfile, contentType='image/png'),
width=width, height=height, coordmap=coordmap
))
})
#' @export
#' @method as.tags shiny.render.function
as.tags.shiny.render.function <- function(x, ..., inline = FALSE) {
useRenderFunction(x, inline = inline)
}
#' Image file output
#'
#' Renders a reactive image that is suitable for assigning to an \code{output}
#' Renders a reactive image that is suitable for assigning to an \code{output}
#' slot.
#'
#' The expression \code{expr} must return a list containing the attributes for
@@ -221,8 +129,8 @@ renderPlot <- function(expr, width='auto', height='auto', res=72, ...,
renderImage <- function(expr, env=parent.frame(), quoted=FALSE,
deleteFile=TRUE) {
installExprFunction(expr, "func", env, quoted)
return(function(shinysession, name, ...) {
return(markRenderFunction(imageOutput, function(shinysession, name, ...) {
imageinfo <- func()
# Should the file be deleted after being sent? If .deleteFile not set or if
# TRUE, then delete; otherwise don't delete.
@@ -231,11 +139,7 @@ renderImage <- function(expr, env=parent.frame(), quoted=FALSE,
}
# If contentType not specified, autodetect based on extension
if (is.null(imageinfo$contentType)) {
contentType <- getContentType(sub('^.*\\.', '', basename(imageinfo$src)))
} else {
contentType <- imageinfo$contentType
}
contentType <- imageinfo$contentType %OR% getContentType(imageinfo$src)
# Extra values are everything in imageinfo except 'src' and 'contentType'
extra_attr <- imageinfo[!names(imageinfo) %in% c('src', 'contentType')]
@@ -243,115 +147,69 @@ renderImage <- function(expr, env=parent.frame(), quoted=FALSE,
# Return a list with src, and other img attributes
c(src = shinysession$fileUrl(name, file=imageinfo$src, contentType=contentType),
extra_attr)
})
}))
}
#' Table Output
#'
#' Creates a reactive table that is suitable for assigning to an \code{output}
#' slot.
#'
#' The corresponding HTML output tag should be \code{div} and have the CSS class
#' name \code{shiny-html-output}.
#'
#' @param expr An expression that returns an R object that can be used with
#' \code{\link[xtable]{xtable}}.
#' @param ... Arguments to be passed through to \code{\link[xtable]{xtable}} and
#' \code{\link[xtable]{print.xtable}}.
#' @param env The environment in which to evaluate \code{expr}.
#' @param quoted Is \code{expr} a quoted expression (with \code{quote()})? This
#' is useful if you want to save an expression in a variable.
#' @param func A function that returns an R object that can be used with
#' \code{\link[xtable]{xtable}} (deprecated; use \code{expr} instead).
#'
#' @export
renderTable <- function(expr, ..., env=parent.frame(), quoted=FALSE, func=NULL) {
if (!is.null(func)) {
shinyDeprecated(msg="renderTable: argument 'func' is deprecated. Please use 'expr' instead.")
} else {
installExprFunction(expr, "func", env, quoted)
}
function() {
classNames <- getOption('shiny.table.class', 'data table table-bordered table-condensed')
data <- func()
if (is.null(data) || identical(data, data.frame()))
return("")
return(paste(
capture.output(
print(xtable(data, ...),
type='html',
html.table.attributes=paste('class="',
htmlEscape(classNames, TRUE),
'"',
sep=''), ...)),
collapse="\n"))
}
}
#' Printable Output
#'
#' Makes a reactive version of the given function that captures any printed
#' output, and also captures its printable result (unless
#' \code{\link{invisible}}), into a string. The resulting function is suitable
#'
#' Makes a reactive version of the given function that captures any printed
#' output, and also captures its printable result (unless
#' \code{\link{invisible}}), into a string. The resulting function is suitable
#' for assigning to an \code{output} slot.
#'
#' The corresponding HTML output tag can be anything (though \code{pre} is
#'
#' The corresponding HTML output tag can be anything (though \code{pre} is
#' recommended if you need a monospace font and whitespace preserved) and should
#' have the CSS class name \code{shiny-text-output}.
#'
#' The result of executing \code{func} will be printed inside a
#'
#' The result of executing \code{func} will be printed inside a
#' \code{\link[utils]{capture.output}} call.
#'
#' Note that unlike most other Shiny output functions, if the given function
#' returns \code{NULL} then \code{NULL} will actually be visible in the output.
#'
#' Note that unlike most other Shiny output functions, if the given function
#' returns \code{NULL} then \code{NULL} will actually be visible in the output.
#' To display nothing, make your function return \code{\link{invisible}()}.
#'
#' @param expr An expression that may print output and/or return a printable R
#'
#' @param expr An expression that may print output and/or return a printable R
#' object.
#' @param env The environment in which to evaluate \code{expr}.
#' @param quoted Is \code{expr} a quoted expression (with \code{quote()})? This
#' @param func A function that may print output and/or return a printable R
#' @param func A function that may print output and/or return a printable R
#' object (deprecated; use \code{expr} instead).
#'
#' @seealso \code{\link{renderText}} for displaying the value returned from a
#' @param width The value for \code{\link{options}('width')}.
#' @seealso \code{\link{renderText}} for displaying the value returned from a
#' function, instead of the printed output.
#'
#' @example res/text-example.R
#'
#'
#' @export
renderPrint <- function(expr, env=parent.frame(), quoted=FALSE, func=NULL) {
renderPrint <- function(expr, env = parent.frame(), quoted = FALSE, func = NULL,
width = getOption('width')) {
if (!is.null(func)) {
shinyDeprecated(msg="renderPrint: argument 'func' is deprecated. Please use 'expr' instead.")
} else {
installExprFunction(expr, "func", env, quoted)
}
function() {
return(paste(capture.output({
result <- withVisible(func())
if (result$visible)
print(result$value)
}), collapse="\n"))
}
markRenderFunction(verbatimTextOutput, function() {
op <- options(width = width)
on.exit(options(op), add = TRUE)
paste(utils::capture.output(func()), collapse = "\n")
})
}
#' Text Output
#'
#' Makes a reactive version of the given function that also uses
#' \code{\link[base]{cat}} to turn its result into a single-element character
#'
#' Makes a reactive version of the given function that also uses
#' \code{\link[base]{cat}} to turn its result into a single-element character
#' vector.
#'
#' The corresponding HTML output tag can be anything (though \code{pre} is
#'
#' The corresponding HTML output tag can be anything (though \code{pre} is
#' recommended if you need a monospace font and whitespace preserved) and should
#' have the CSS class name \code{shiny-text-output}.
#'
#' The result of executing \code{func} will passed to \code{cat}, inside a
#'
#' The result of executing \code{func} will passed to \code{cat}, inside a
#' \code{\link[utils]{capture.output}} call.
#'
#'
#' @param expr An expression that returns an R object that can be used as an
#' argument to \code{cat}.
#' @param env The environment in which to evaluate \code{expr}.
@@ -359,12 +217,12 @@ renderPrint <- function(expr, env=parent.frame(), quoted=FALSE, func=NULL) {
#' is useful if you want to save an expression in a variable.
#' @param func A function that returns an R object that can be used as an
#' argument to \code{cat}.(deprecated; use \code{expr} instead).
#'
#'
#' @seealso \code{\link{renderPrint}} for capturing the print output of a
#' function, rather than the returned text value.
#'
#' @example res/text-example.R
#'
#'
#' @export
renderText <- function(expr, env=parent.frame(), quoted=FALSE, func=NULL) {
if (!is.null(func)) {
@@ -373,36 +231,36 @@ renderText <- function(expr, env=parent.frame(), quoted=FALSE, func=NULL) {
installExprFunction(expr, "func", env, quoted)
}
function() {
markRenderFunction(textOutput, function() {
value <- func()
return(paste(capture.output(cat(value)), collapse="\n"))
}
return(paste(utils::capture.output(cat(value)), collapse="\n"))
})
}
#' UI Output
#'
#'
#' \bold{Experimental feature.} Makes a reactive version of a function that
#' generates HTML using the Shiny UI library.
#'
#'
#' The corresponding HTML output tag should be \code{div} and have the CSS class
#' name \code{shiny-html-output} (or use \code{\link{uiOutput}}).
#'
#' @param expr An expression that returns a Shiny tag object, \code{\link{HTML}},
#'
#' @param expr An expression that returns a Shiny tag object, \code{\link{HTML}},
#' or a list of such objects.
#' @param env The environment in which to evaluate \code{expr}.
#' @param quoted Is \code{expr} a quoted expression (with \code{quote()})? This
#' is useful if you want to save an expression in a variable.
#' @param func A function that returns a Shiny tag object, \code{\link{HTML}},
#' @param func A function that returns a Shiny tag object, \code{\link{HTML}},
#' or a list of such objects (deprecated; use \code{expr} instead).
#'
#'
#' @seealso conditionalPanel
#'
#'
#' @export
#' @examples
#' \dontrun{
#' output$moreControls <- renderUI({
#' list(
#'
#'
#' )
#' })
#' }
@@ -413,39 +271,51 @@ renderUI <- function(expr, env=parent.frame(), quoted=FALSE, func=NULL) {
installExprFunction(expr, "func", env, quoted)
}
function() {
markRenderFunction(uiOutput, function(shinysession, name, ...) {
result <- func()
if (is.null(result) || length(result) == 0)
return(NULL)
# Wrap result in tagList in case it is an ordinary list
return(as.character(tagList(result)))
}
result <- takeSingletons(result, shinysession$singletons, desingleton=FALSE)$ui
result <- surroundSingletons(result)
dependencies <- lapply(resolveDependencies(findDependencies(result)),
createWebDependency)
names(dependencies) <- NULL
# renderTags returns a list with head, singletons, and html
output <- list(
html = doRenderTags(result),
deps = dependencies
)
return(output)
})
}
#' File Downloads
#'
#'
#' Allows content from the Shiny application to be made available to the user as
#' file downloads (for example, downloading the currently visible data as a CSV
#' file). Both filename and contents can be calculated dynamically at the time
#' the user initiates the download. Assign the return value to a slot on
#' \code{output} in your server function, and in the UI use
#' file downloads (for example, downloading the currently visible data as a CSV
#' file). Both filename and contents can be calculated dynamically at the time
#' the user initiates the download. Assign the return value to a slot on
#' \code{output} in your server function, and in the UI use
#' \code{\link{downloadButton}} or \code{\link{downloadLink}} to make the
#' download available.
#'
#' @param filename A string of the filename, including extension, that the
#' user's web browser should default to when downloading the file; or a
#' function that returns such a string. (Reactive values and functions may be
#'
#' @param filename A string of the filename, including extension, that the
#' user's web browser should default to when downloading the file; or a
#' function that returns such a string. (Reactive values and functions may be
#' used from this function.)
#' @param content A function that takes a single argument \code{file} that is a
#' @param content A function that takes a single argument \code{file} that is a
#' file path (string) of a nonexistent temp file, and writes the content to
#' that file path. (Reactive values and functions may be used from this
#' function.)
#' @param contentType A string of the download's
#' \href{http://en.wikipedia.org/wiki/Internet_media_type}{content type}, for
#' example \code{"text/csv"} or \code{"image/png"}. If \code{NULL} or
#' \code{NA}, the content type will be guessed based on the filename
#' @param contentType A string of the download's
#' \href{http://en.wikipedia.org/wiki/Internet_media_type}{content type}, for
#' example \code{"text/csv"} or \code{"image/png"}. If \code{NULL} or
#' \code{NA}, the content type will be guessed based on the filename
#' extension, or \code{application/octet-stream} if the extension is unknown.
#'
#'
#' @examples
#' \dontrun{
#' # In server.R:
@@ -457,16 +327,16 @@ renderUI <- function(expr, env=parent.frame(), quoted=FALSE, func=NULL) {
#' write.csv(data, file)
#' }
#' )
#'
#'
#' # In ui.R:
#' downloadLink('downloadData', 'Download')
#' }
#'
#'
#' @export
downloadHandler <- function(filename, content, contentType=NA) {
return(function(shinysession, name, ...) {
return(markRenderFunction(downloadButton, function(shinysession, name, ...) {
shinysession$registerDownload(name, filename, contentType, content)
})
}))
}
#' Table output with the JavaScript library DataTables
@@ -475,26 +345,133 @@ downloadHandler <- function(filename, content, contentType=NA) {
#' matrix), which will be rendered with the DataTables library. Paging,
#' searching, filtering, and sorting can be done on the R side using Shiny as
#' the server infrastructure.
#'
#' For the \code{options} argument, the character elements that have the class
#' \code{"AsIs"} (usually returned from \code{\link{I}()}) will be evaluated in
#' JavaScript. This is useful when the type of the option value is not supported
#' in JSON, e.g., a JavaScript function, which can be obtained by evaluating a
#' character string. Note this only applies to the root-level elements of the
#' options list, and the \code{I()} notation does not work for lower-level
#' elements in the list.
#' @param expr An expression that returns a data frame or a matrix.
#' @param options A list of initialization options to be passed to DataTables.
#' @param options A list of initialization options to be passed to DataTables,
#' or a function to return such a list.
#' @param searchDelay The delay for searching, in milliseconds (to avoid too
#' frequent search requests).
#' @param callback A JavaScript function to be applied to the DataTable object.
#' This is useful for DataTables plug-ins, which often require the DataTable
#' instance to be available (\url{http://datatables.net/extensions/}).
#' @param escape Whether to escape HTML entities in the table: \code{TRUE} means
#' to escape the whole table, and \code{FALSE} means not to escape it.
#' Alternatively, you can specify numeric column indices or column names to
#' indicate which columns to escape, e.g. \code{1:5} (the first 5 columns),
#' \code{c(1, 3, 4)}, or \code{c(-1, -3)} (all columns except the first and
#' third), or \code{c('Species', 'Sepal.Length')}.
#' @references \url{http://datatables.net}
#' @note This function only provides the server-side version of DataTables
#' (using R to process the data object on the server side). There is a
#' separate package \pkg{DT} (\url{https://github.com/rstudio/DT}) that allows
#' you to create both server-side and client-side DataTables, and supports
#' additional DataTables features. Consider using \code{DT::renderDataTable()}
#' and \code{DT::dataTableOutput()} (see
#' \url{http://rstudio.github.io/DT/shiny.html} for more information).
#' @export
#' @inheritParams renderPlot
#' @examples
#' ## Only run this example in interactive R sessions
#' if (interactive()) {
#' # pass a callback function to DataTables using I()
#' shinyApp(
#' ui = fluidPage(
#' fluidRow(
#' column(12,
#' dataTableOutput('table')
#' )
#' )
#' ),
#' server = function(input, output) {
#' output$table <- renderDataTable(iris,
#' options = list(
#' pageLength = 5,
#' initComplete = I("function(settings, json) {alert('Done.');}")
#' )
#' )
#' }
#' )
#' }
renderDataTable <- function(expr, options = NULL, searchDelay = 500,
env=parent.frame(), quoted=FALSE) {
callback = 'function(oTable) {}', escape = TRUE,
env = parent.frame(), quoted = FALSE) {
installExprFunction(expr, "func", env, quoted)
function(shinysession, name, ...) {
markRenderFunction(dataTableOutput, function(shinysession, name, ...) {
if (is.function(options)) options <- options()
options <- checkDT9(options)
res <- checkAsIs(options)
data <- func()
if (length(dim(data)) != 2) return() # expects a rectangular data object
action <- shinysession$registerDataTable(name, data)
list(colnames = colnames(data), action = action, options = options,
searchDelay = searchDelay)
}
if (is.data.frame(data)) data <- as.data.frame(data)
action <- shinysession$registerDataObj(name, data, dataTablesJSON)
colnames <- colnames(data)
# if escape is column names, turn names to numeric indices
if (is.character(escape)) {
escape <- stats::setNames(seq_len(ncol(data)), colnames)[escape]
if (any(is.na(escape)))
stop("Some column names in the 'escape' argument not found in data")
}
colnames[escape] <- htmlEscape(colnames[escape])
if (!is.logical(escape)) {
if (!is.numeric(escape))
stop("'escape' must be TRUE, FALSE, or a numeric vector, or column names")
escape <- paste(escape, collapse = ',')
}
list(
colnames = colnames, action = action, options = res$options,
evalOptions = if (length(res$eval)) I(res$eval), searchDelay = searchDelay,
callback = paste(callback, collapse = '\n'), escape = escape
)
})
}
# a data frame containing the DataTables 1.9 and 1.10 names
DT10Names <- function() {
rbind(
utils::read.table(
system.file('www/shared/datatables/upgrade1.10.txt', package = 'shiny'),
stringsAsFactors = FALSE
),
c('aoColumns', 'Removed') # looks like an omission on the upgrade guide
)
}
# check DataTables 1.9.x options, and give instructions for upgrading to 1.10.x
checkDT9 <- function(options) {
nms <- names(options)
if (length(nms) == 0L) return(options)
DT10 <- DT10Names()
# e.g. the top level option name for oLanguage.sSearch should be oLanguage
i <- nms %in% gsub('[.].*', '', DT10[, 1])
if (!any(i)) return(options) # did not see old option names, ready to go!
msg <- paste(
'shiny (>= 0.10.2) has upgraded DataTables from 1.9.4 to 1.10.2, ',
'and DataTables 1.10.x uses different parameter names with 1.9.x. ',
'Please follow the upgrade guide https://datatables.net/upgrade/1.10-convert',
' to change your DataTables parameter names:\n\n',
paste(utils::formatUL(nms[i]), collapse = '\n'), '\n', sep = ''
)
j <- gsub('[.].*', '', DT10[, 1]) %in% nms
# I cannot help you upgrade automatically in these cases, so I have to stop
if (any(grepl('[.]', DT10[j, 1])) || any(grepl('[.]', DT10[j, 2]))) stop(msg)
warning(msg)
nms10 <- DT10[match(nms[i], DT10[, 1]), 2]
if (any(nms10 == 'Removed')) stop(
"These parameters have been removed in DataTables 1.10.x:\n\n",
paste(utils::formatUL(nms[i][nms10 == 'Removed']), collapse = '\n'),
"\n\n", msg
)
names(options)[i] <- nms10
options
}
# Deprecated functions ------------------------------------------------------

179
R/showcase.R Normal file
View File

@@ -0,0 +1,179 @@
#' @include globals.R
NULL
# Given the name of a license, return the appropriate link HTML for the
# license, which may just be the name of the license if the name is
# unrecognized.
#
# Recognizes the 'standard' set of licenses used for R packages
# (see http://cran.r-project.org/doc/manuals/R-exts.html)
licenseLink <- function(licenseName) {
licenses <- list(
"GPL-2" = "https://gnu.org/licenses/gpl-2.0.txt",
"GPL-3" = "https://gnu.org/licenses/gpl-3.0.txt",
"LGPL-3" = "https://www.gnu.org/licenses/lgpl-3.0.txt",
"LGPL-2" = "http://www.gnu.org/licenses/old-licenses/lgpl-2.0.txt",
"LGPL-2.1" = "http://www.gnu.org/licenses/lgpl-2.1.txt",
"AGPL-3" = "http://www.gnu.org/licenses/agpl-3.0.txt",
"Artistic-2.0" = "http://www.r-project.org/Licenses/Artistic-2.0",
"BSD_2_clause" = "http://www.r-project.org/Licenses/BSD_2_clause",
"BSD_3_clause" = "http://www.r-project.org/Licenses/BSD_3_clause",
"MIT" = "http://www.r-project.org/Licenses/MIT")
if (exists(licenseName, where = licenses)) {
tags$a(href=licenses[[licenseName]], licenseName)
} else {
licenseName
}
}
# Returns tags containing showcase directives intended for the <HEAD> of the
# document.
showcaseHead <- function() {
deps <- list(
htmlDependency("jqueryui", "1.11.4", c(href="shared/jqueryui"),
script = "jquery-ui.min.js"),
htmlDependency("showdown", "0.3.1", c(href="shared/showdown/compressed"),
script = "showdown.js"),
htmlDependency("highlight.js", "6.2", c(href="shared/highlight"),
script = "highlight.pack.js")
)
mdfile <- file.path.ci(getwd(), 'Readme.md')
html <- with(tags, tagList(
script(src="shared/shiny-showcase.js"),
link(rel="stylesheet", type="text/css",
href="shared/highlight/rstudio.css"),
link(rel="stylesheet", type="text/css",
href="shared/shiny-showcase.css"),
if (file.exists(mdfile))
script(type="text/markdown", id="showcase-markdown-content",
paste(readUTF8(mdfile), collapse="\n"))
else ""
))
return(attachDependencies(html, deps))
}
# Returns tags containing the application metadata (title and author) in
# showcase mode.
appMetadata <- function(desc) {
cols <- colnames(desc)
if ("Title" %in% cols)
with(tags, h4(class="text-muted shiny-showcase-apptitle", desc[1,"Title"],
if ("Author" %in% cols) small(
br(), "by",
if ("AuthorUrl" %in% cols)
a(href=desc[1,"AuthorUrl"], class="shiny-showcase-appauthor",
desc[1,"Author"])
else
desc[1,"Author"],
if ("AuthorEmail" %in% cols)
a(href=paste("mailto:", desc[1,"AuthorEmail"], sep = ''),
class="shiny-showcase-appauthoreemail",
desc[1,"AuthorEmail"])
else "")
else ""))
else ""
}
# Returns tags containing the application's code in Bootstrap-style tabs in
# showcase mode.
showcaseCodeTabs <- function(codeLicense) {
rFiles <- list.files(pattern = "\\.[rR]$")
with(tags, div(id="showcase-code-tabs",
a(id="showcase-code-position-toggle",
class="btn btn-default btn-sm",
onclick="toggleCodePosition()",
icon("level-up"),
"show with app"),
ul(class="nav nav-tabs",
lapply(rFiles, function(rFile) {
li(class=if (tolower(rFile) %in% c("app.r", "server.r")) "active" else "",
a(href=paste("#", gsub(".", "_", rFile, fixed=TRUE),
"_code", sep=""),
"data-toggle"="tab", rFile))
})),
div(class="tab-content", id="showcase-code-content",
lapply(rFiles, function(rFile) {
div(class=paste("tab-pane",
if (tolower(rFile) %in% c("app.r", "server.r")) " active"
else "",
sep=""),
id=paste(gsub(".", "_", rFile, fixed=TRUE),
"_code", sep=""),
pre(class="shiny-code",
# we need to prevent the indentation of <code> ... </code>
HTML(format(tags$code(
class="language-r",
paste(readUTF8(file.path.ci(getwd(), rFile)), collapse="\n")
), indent = FALSE))))
})),
codeLicense))
}
# Returns tags containing the showcase application information (readme and
# code).
showcaseAppInfo <- function() {
descfile <- file.path.ci(getwd(), "DESCRIPTION")
hasDesc <- file.exists(descfile)
readmemd <- file.path.ci(getwd(), "Readme.md")
hasReadme <- file.exists(readmemd)
if (hasDesc) {
con <- textConnection(readUTF8(descfile))
on.exit(close(con), add = TRUE)
desc <- read.dcf(con)
}
with(tags,
div(class="container-fluid shiny-code-container well",
id="showcase-well",
div(class="row",
if (hasDesc || hasReadme) {
div(id="showcase-app-metadata", class="col-sm-4",
if (hasDesc) appMetadata(desc) else "",
if (hasReadme) div(id="readme-md"))
} else "",
div(id="showcase-code-inline",
class=if (hasReadme || hasDesc) "col-sm-8" else "col-sm-10 col-sm-offset-1",
showcaseCodeTabs(
if (hasDesc && "License" %in% colnames(desc)) {
small(class="showcase-code-license text-muted",
"Code license: ",
licenseLink(desc[1,"License"]))
} else "")))))
}
# Returns the body of the showcase document, given the HTML it should wrap.
showcaseBody <- function(htmlBody) {
with(tags, tagList(
table(id="showcase-app-code",
tr(td(id="showcase-app-container",
class="showcase-app-container-expanded",
htmlBody,
td(id="showcase-sxs-code",
class="showcase-sxs-code-collapsed")))),
showcaseAppInfo()))
}
# Sets the defaults for showcase mode (for app boot).
setShowcaseDefault <- function(showcaseDefault) {
.globals$showcaseDefault <- showcaseDefault
.globals$showcaseOverride <- as.logical(showcaseDefault)
}
# Given a UI tag/tagList, wrap it in appropriate tags for showcase mode.
showcaseUI <- function(ui) {
# If top-level tag is a body, replace its children with children wrapped in
# showcase stuff.
if (inherits(ui, "shiny.tag") && ui$name == "body") {
ui$children <- showcaseUI(ui$children)
return(ui)
}
tagList(
tags$head(showcaseHead()),
showcaseBody(ui)
)
}

View File

@@ -1,133 +0,0 @@
hasDecimals <- function(value) {
truncatedValue <- round(value)
return (!identical(value, truncatedValue))
}
#' Animation Options
#'
#' Creates an options object for customizing animations for \link{sliderInput}.
#'
#' @param interval The interval, in milliseconds, between each animation step.
#' @param loop \code{TRUE} to automatically restart the animation when it
#' reaches the end.
#' @param playButton Specifies the appearance of the play button. Valid values
#' are a one-element character vector (for a simple text label), an HTML tag
#' or list of tags (using \code{\link{tag}} and friends), or raw HTML (using
#' \code{\link{HTML}}).
#' @param pauseButton Similar to \code{playButton}, but for the pause button.
#'
#' @export
animationOptions <- function(interval=1000,
loop=FALSE,
playButton=NULL,
pauseButton=NULL) {
list(interval=interval,
loop=loop,
playButton=playButton,
pauseButton=pauseButton)
}
# Create a new slider control (list of slider input element and the script
# tag used to configure it). This is a lower level control that should
# be wrapped in an "input" construct (e.g. sliderInput in bootstrap.R)
#
# this is a wrapper for: https://github.com/egorkhmelev/jslider
# (www/shared/slider contains js, css, and img dependencies)
slider <- function(inputId, min, max, value, step = NULL, ...,
round=FALSE, format='#,##0.#####', locale='us',
ticks=TRUE, animate=FALSE) {
# validate inputId
inputId <- as.character(inputId)
if (!is.character(inputId))
stop("inputId not specified")
# validate numeric inputs
if (!is.numeric(value) || !is.numeric(min) || !is.numeric(max))
stop("min, max, and value must all be numeric values")
else if (min(value) < min)
stop(paste("slider initial value", value,
"is less than the specified minimum"))
else if (max(value) > max)
stop(paste("slider initial value", value,
"is greater than the specified maximum"))
else if (min > max)
stop(paste("slider maximum is greater than minimum"))
else if (!is.null(step)) {
if (!is.numeric(step))
stop("step is not a numeric value")
if (step > (max - min))
stop("step is greater than range")
}
# step
range <- max - min
if (is.null(step)) {
# short range or decimals means continuous decimal
if (range < 2 || hasDecimals(min) || hasDecimals(max))
step <- range / 250 # ~ one step per pixel
else
step = 1
}
# Default state is to not have ticks
if (identical(ticks, TRUE)) {
# Automatic ticks
tickCount <- (range / step) + 1
if (tickCount <= 26)
ticks <- paste(rep('|', floor(tickCount)), collapse=';')
else {
ticks <- NULL
# # This is a smarter auto-tick algorithm, but to be truly useful
# # we need jslider to be able to space ticks irregularly
# tickSize <- 10^(floor(log10(range/0.39)))
# if ((range / tickSize) == floor(range / tickSize)) {
# ticks <- paste(rep('|', (range / tickSize) + 1), collapse=';')
# }
# else {
# ticks <- NULL
# }
}
}
else if (is.numeric(ticks) && length(ticks) == 1) {
# Use n ticks
ticks <- paste(rep('|', ticks), collapse=';')
}
else if (length(ticks) > 1 && (is.numeric(ticks) || is.character(ticks))) {
# Explicit ticks
ticks <- paste(ticks, collapse=';')
}
else {
ticks <- NULL
}
# build slider
sliderFragment <- list(tags$input(
id=inputId, type="slider",
name=inputId, value=paste(value, collapse=';'), class="jslider",
'data-from'=min, 'data-to'=max, 'data-step'=step,
'data-skin'='plastic', 'data-round'=round, 'data-locale'=locale,
'data-format'=format, 'data-scale'=ticks,
'data-smooth'=FALSE))
if (identical(animate, TRUE))
animate <- animationOptions()
if (!is.null(animate) && !identical(animate, FALSE)) {
if (is.null(animate$playButton))
animate$playButton <- 'Play'
if (is.null(animate$pauseButton))
animate$pauseButton <- 'Pause'
sliderFragment[[length(sliderFragment)+1]] <-
tags$div(class='slider-animate-container',
tags$a(href='#',
class='slider-animate-button',
'data-target-id'=inputId,
'data-interval'=animate$interval,
'data-loop'=animate$loop,
tags$span(class='play', animate$playButton),
tags$span(class='pause', animate$pauseButton)))
}
return(sliderFragment)
}

70
R/stack.R Normal file
View File

@@ -0,0 +1,70 @@
# A Stack object backed by a list. The backing list will grow or shrink as
# the stack changes in size.
Stack <- R6Class(
'Stack',
portable = FALSE,
class = FALSE,
public = list(
initialize = function(init = 20L) {
# init is the initial size of the list. It is also used as the minimum
# size of the list as it shrinks.
private$stack <- vector("list", init)
private$init <- init
},
push = function(..., .list = NULL) {
args <- c(list(...), .list)
new_size <- count + length(args)
# Grow if needed; double in size
while (new_size > length(stack)) {
stack[length(stack) * 2] <<- list(NULL)
}
stack[count + seq_along(args)] <<- args
count <<- new_size
invisible(self)
},
pop = function() {
if (count == 0L)
return(NULL)
value <- stack[[count]]
stack[count] <<- list(NULL)
count <<- count - 1L
# Shrink list if < 1/4 of the list is used, down to a minimum size of `init`
len <- length(stack)
if (len > init && count < len/4) {
new_len <- max(init, ceiling(len/2))
stack <<- stack[seq_len(new_len)]
}
value
},
peek = function() {
if (count == 0L)
return(NULL)
stack[[count]]
},
size = function() {
count
},
# Return the entire stack as a list, where the first item in the list is the
# oldest item in the stack, and the last item is the most recently added.
as_list = function() {
stack[seq_len(count)]
}
),
private = list(
stack = NULL, # A list that holds the items
count = 0L, # Current number of items in the stack
init = 20L # Initial and minimum size of the stack
)
)

402
R/tags.R
View File

@@ -1,402 +0,0 @@
htmlEscape <- local({
.htmlSpecials <- list(
`&` = '&amp;',
`<` = '&lt;',
`>` = '&gt;'
)
.htmlSpecialsPattern <- paste(names(.htmlSpecials), collapse='|')
.htmlSpecialsAttrib <- c(
.htmlSpecials,
`'` = '&#39;',
`"` = '&quot;',
`\r` = '&#13;',
`\n` = '&#10;'
)
.htmlSpecialsPatternAttrib <- paste(names(.htmlSpecialsAttrib), collapse='|')
function(text, attribute=TRUE) {
pattern <- if(attribute)
.htmlSpecialsPatternAttrib
else
.htmlSpecialsPattern
# Short circuit in the common case that there's nothing to escape
if (!grepl(pattern, text))
return(text)
specials <- if(attribute)
.htmlSpecialsAttrib
else
.htmlSpecials
for (chr in names(specials)) {
text <- gsub(chr, specials[[chr]], text, fixed=TRUE)
}
return(text)
}
})
isTag <- function(x) {
inherits(x, "shiny.tag")
}
#' @S3method print shiny.tag
print.shiny.tag <- function(x, ...) {
print(as.character(x), ...)
}
#' @S3method format shiny.tag
format.shiny.tag <- function(x, ...) {
as.character.shiny.tag(x)
}
#' @S3method as.character shiny.tag
as.character.shiny.tag <- function(x, ...) {
f = file()
on.exit(close(f))
textWriter <- function(text) {
cat(text, file=f)
}
tagWrite(x, textWriter)
return(HTML(paste(readLines(f, warn=FALSE), collapse='\n')))
}
#' @S3method print shiny.tag.list
print.shiny.tag.list <- print.shiny.tag
#' @S3method format shiny.tag.list
format.shiny.tag.list <- format.shiny.tag
#' @S3method as.character shiny.tag.list
as.character.shiny.tag.list <- as.character.shiny.tag
normalizeText <- function(text) {
if (!is.null(attr(text, "html")))
text
else
htmlEscape(text, attribute=FALSE)
}
#' @export
tagList <- function(...) {
lst <- list(...)
class(lst) <- c("shiny.tag.list", "list")
return(lst)
}
#' @export
tagAppendChild <- function(tag, child) {
tag$children[[length(tag$children)+1]] <- child
tag
}
#' @export
tagAppendChildren <- function(tag, ..., list = NULL) {
tag$children <- c(tag$children, c(list(...), list))
tag
}
#' @export
tagSetChildren <- function(tag, ..., list = NULL) {
tag$children <- c(list(...), list)
tag
}
#' @export
tag <- function(`_tag_name`, varArgs) {
# Get arg names; if not a named list, use vector of empty strings
varArgsNames <- names(varArgs)
if (is.null(varArgsNames))
varArgsNames <- character(length=length(varArgs))
# Named arguments become attribs, dropping NULL values
named_idx <- nzchar(varArgsNames)
attribs <- dropNulls(varArgs[named_idx])
# Unnamed arguments are flattened and added as children.
# Use unname() to remove the names attribute from the list, which would
# consist of empty strings anyway.
children <- flattenTags(unname(varArgs[!named_idx]))
# Return tag data structure
structure(
list(name = `_tag_name`,
attribs = attribs,
children = children),
class = "shiny.tag"
)
}
tagWrite <- function(tag, textWriter, indent=0, context = NULL, eol = "\n") {
# optionally process a list of tags
if (!isTag(tag) && is.list(tag)) {
sapply(tag, function(t) tagWrite(t, textWriter, indent, context))
return (NULL)
}
# first call optional filter -- exit function if it returns false
if (!is.null(context) && !is.null(context$filter) && !context$filter(tag))
return (NULL)
# compute indent text
indentText <- paste(rep(" ", indent*2), collapse="")
# Check if it's just text (may either be plain-text or HTML)
if (is.character(tag)) {
textWriter(paste(indentText, normalizeText(tag), eol, sep=""))
return (NULL)
}
# write tag name
textWriter(paste(indentText, "<", tag$name, sep=""))
# write attributes
for (attrib in names(tag$attribs)) {
attribValue <- tag$attribs[[attrib]]
if (!is.na(attribValue)) {
if (is.logical(attribValue))
attribValue <- tolower(attribValue)
text <- htmlEscape(attribValue, attribute=TRUE)
textWriter(paste(" ", attrib,"=\"", text, "\"", sep=""))
}
else {
textWriter(paste(" ", attrib, sep=""))
}
}
# write any children
if (length(tag$children) > 0) {
textWriter(">")
# special case for a single child text node (skip newlines and indentation)
if ((length(tag$children) == 1) && is.character(tag$children[[1]]) ) {
tagWrite(tag$children[[1]], textWriter, 0, context, "")
textWriter(paste("</", tag$name, ">", eol, sep=""))
}
else {
textWriter("\n")
for (child in tag$children)
tagWrite(child, textWriter, indent+1, context)
textWriter(paste(indentText, "</", tag$name, ">", eol, sep=""))
}
}
else {
# only self-close void elements
# (see: http://dev.w3.org/html5/spec/single-page.html#void-elements)
if (tag$name %in% c("area", "base", "br", "col", "command", "embed", "hr",
"img", "input", "keygen", "link", "meta", "param",
"source", "track", "wbr")) {
textWriter(paste("/>", eol, sep=""))
}
else {
textWriter(paste("></", tag$name, ">", eol, sep=""))
}
}
}
# environment used to store all available tags
#' @export
tags <- list(
a = function(...) tag("a", list(...)),
abbr = function(...) tag("abbr", list(...)),
address = function(...) tag("address", list(...)),
area = function(...) tag("area", list(...)),
article = function(...) tag("article", list(...)),
aside = function(...) tag("aside", list(...)),
audio = function(...) tag("audio", list(...)),
b = function(...) tag("b", list(...)),
base = function(...) tag("base", list(...)),
bdi = function(...) tag("bdi", list(...)),
bdo = function(...) tag("bdo", list(...)),
blockquote = function(...) tag("blockquote", list(...)),
body = function(...) tag("body", list(...)),
br = function(...) tag("br", list(...)),
button = function(...) tag("button", list(...)),
canvas = function(...) tag("canvas", list(...)),
caption = function(...) tag("caption", list(...)),
cite = function(...) tag("cite", list(...)),
code = function(...) tag("code", list(...)),
col = function(...) tag("col", list(...)),
colgroup = function(...) tag("colgroup", list(...)),
command = function(...) tag("command", list(...)),
data = function(...) tag("data", list(...)),
datalist = function(...) tag("datalist", list(...)),
dd = function(...) tag("dd", list(...)),
del = function(...) tag("del", list(...)),
details = function(...) tag("details", list(...)),
dfn = function(...) tag("dfn", list(...)),
div = function(...) tag("div", list(...)),
dl = function(...) tag("dl", list(...)),
dt = function(...) tag("dt", list(...)),
em = function(...) tag("em", list(...)),
embed = function(...) tag("embed", list(...)),
eventsource = function(...) tag("eventsource", list(...)),
fieldset = function(...) tag("fieldset", list(...)),
figcaption = function(...) tag("figcaption", list(...)),
figure = function(...) tag("figure", list(...)),
footer = function(...) tag("footer", list(...)),
form = function(...) tag("form", list(...)),
h1 = function(...) tag("h1", list(...)),
h2 = function(...) tag("h2", list(...)),
h3 = function(...) tag("h3", list(...)),
h4 = function(...) tag("h4", list(...)),
h5 = function(...) tag("h5", list(...)),
h6 = function(...) tag("h6", list(...)),
head = function(...) tag("head", list(...)),
header = function(...) tag("header", list(...)),
hgroup = function(...) tag("hgroup", list(...)),
hr = function(...) tag("hr", list(...)),
html = function(...) tag("html", list(...)),
i = function(...) tag("i", list(...)),
iframe = function(...) tag("iframe", list(...)),
img = function(...) tag("img", list(...)),
input = function(...) tag("input", list(...)),
ins = function(...) tag("ins", list(...)),
kbd = function(...) tag("kbd", list(...)),
keygen = function(...) tag("keygen", list(...)),
label = function(...) tag("label", list(...)),
legend = function(...) tag("legend", list(...)),
li = function(...) tag("li", list(...)),
link = function(...) tag("link", list(...)),
mark = function(...) tag("mark", list(...)),
map = function(...) tag("map", list(...)),
menu = function(...) tag("menu", list(...)),
meta = function(...) tag("meta", list(...)),
meter = function(...) tag("meter", list(...)),
nav = function(...) tag("nav", list(...)),
noscript = function(...) tag("noscript", list(...)),
object = function(...) tag("object", list(...)),
ol = function(...) tag("ol", list(...)),
optgroup = function(...) tag("optgroup", list(...)),
option = function(...) tag("option", list(...)),
output = function(...) tag("output", list(...)),
p = function(...) tag("p", list(...)),
param = function(...) tag("param", list(...)),
pre = function(...) tag("pre", list(...)),
progress = function(...) tag("progress", list(...)),
q = function(...) tag("q", list(...)),
ruby = function(...) tag("ruby", list(...)),
rp = function(...) tag("rp", list(...)),
rt = function(...) tag("rt", list(...)),
s = function(...) tag("s", list(...)),
samp = function(...) tag("samp", list(...)),
script = function(...) tag("script", list(...)),
section = function(...) tag("section", list(...)),
select = function(...) tag("select", list(...)),
small = function(...) tag("small", list(...)),
source = function(...) tag("source", list(...)),
span = function(...) tag("span", list(...)),
strong = function(...) tag("strong", list(...)),
style = function(...) tag("style", list(...)),
sub = function(...) tag("sub", list(...)),
summary = function(...) tag("summary", list(...)),
sup = function(...) tag("sup", list(...)),
table = function(...) tag("table", list(...)),
tbody = function(...) tag("tbody", list(...)),
td = function(...) tag("td", list(...)),
textarea = function(...) tag("textarea", list(...)),
tfoot = function(...) tag("tfoot", list(...)),
th = function(...) tag("th", list(...)),
thead = function(...) tag("thead", list(...)),
time = function(...) tag("time", list(...)),
title = function(...) tag("title", list(...)),
tr = function(...) tag("tr", list(...)),
track = function(...) tag("track", list(...)),
u = function(...) tag("u", list(...)),
ul = function(...) tag("ul", list(...)),
var = function(...) tag("var", list(...)),
video = function(...) tag("video", list(...)),
wbr = function(...) tag("wbr", list(...))
)
#' Mark Characters as HTML
#'
#' Marks the given text as HTML, which means the \link{tag} functions will know
#' not to perform HTML escaping on it.
#'
#' @param text The text value to mark with HTML
#' @param ... Any additional values to be converted to character and
#' concatenated together
#' @return The same value, but marked as HTML.
#'
#' @examples
#' el <- div(HTML("I like <u>turtles</u>"))
#' cat(as.character(el))
#'
#' @export
HTML <- function(text, ...) {
htmlText <- c(text, as.character(list(...)))
htmlText <- paste(htmlText, collapse=" ")
attr(htmlText, "html") <- TRUE
htmlText
}
#' Evaluate an expression using the \code{tags}
#'
#' This function makes it simpler to write HTML-generating code. Instead of
#' needing to specify \code{tags} each time a tag function is used, as in
#' \code{tags$div()} and \code{tags$p()}, code inside \code{withTags} is
#' evaluated with \code{tags} searched first, so you can simply use
#' \code{div()} and \code{p()}.
#'
#' If your code uses an object which happens to have the same name as an
#' HTML tag function, such as \code{source()} or \code{summary()}, it will call
#' the tag function. To call the intended (non-tags function), specify the
#' namespace, as in \code{base::source()} or \code{base::summary()}.
#'
#' @param code A set of tags.
#'
#' @examples
#' # Using tags$ each time
#' tags$div(class = "myclass",
#' tags$h3("header"),
#' tags$p("text")
#' )
#'
#' # Equivalent to above, but using withTags
#' withTags(
#' div(class = "myclass",
#' h3("header"),
#' p("text")
#' )
#' )
#'
#'
#' @export
withTags <- function(code) {
eval(substitute(code), envir = as.list(tags), enclos = parent.frame())
}
# Given a list of tags, lists, and other items, return a flat list, where the
# items from the inner, nested lists are pulled to the top level, recursively.
flattenTags <- function(x) {
if (isTag(x)) {
# For tags, wrap them into a list (which will be unwrapped by caller)
list(x)
} else if (is.list(x)) {
if (length(x) == 0) {
# Empty lists are simply returned
x
} else {
# For items that are lists (but not tags), recurse
unlist(lapply(x, flattenTags), recursive = FALSE)
}
} else if (is.character(x)){
# This will preserve attributes if x is a character with attribute,
# like what HTML() produces
list(x)
} else {
# For other items, coerce to character and wrap them into a list (which
# will be unwrapped by caller). Note that this will strip attributes.
list(as.character(x))
}
}

View File

@@ -46,7 +46,7 @@ untar2 <- function(tarfile, files = NULL, list = FALSE, exdir = ".")
mydir.create <- function(path, ...) {
## for Windows' sake
path <- sub("[\\/]$", "", path)
if(file_test("-d", path)) return()
if(utils::file_test("-d", path)) return()
if(!dir.create(path, showWarnings = TRUE, recursive = TRUE, ...))
stop(gettextf("failed to create directory %s", sQuote(path)),
domain = NA)
@@ -141,7 +141,7 @@ untar2 <- function(tarfile, files = NULL, list = FALSE, exdir = ".")
warning(gettextf("failed to copy %s to %s", sQuote(name2), sQuote(name)), domain = NA)
}
} else {
if(.Platform$OS.type == "windows") {
if(isWindows()) {
## this will not work for links to dirs
from <- file.path(dirname(name), name2)
if (!file.copy(from, name))

View File

@@ -4,16 +4,17 @@ now <- function() {
as.numeric(Sys.time()) * 1000
}
TimerCallbacks <- setRefClass(
TimerCallbacks <- R6Class(
'TimerCallbacks',
fields = list(
.nextId = 'integer',
portable = FALSE,
class = FALSE,
public = list(
.nextId = 0L,
.funcs = 'Map',
.times = 'data.frame'
),
methods = list(
.times = data.frame(),
initialize = function() {
.nextId <<- 0L
.funcs <<- Map$new()
},
clear = function() {
.nextId <<- 0L
@@ -23,17 +24,17 @@ TimerCallbacks <- setRefClass(
schedule = function(millis, func) {
id <- .nextId
.nextId <<- .nextId + 1L
t <- now()
# TODO: Horribly inefficient, use a heap instead
.times <<- rbind(.times, data.frame(time=t+millis,
scheduled=t,
id=id))
.times <<- .times[order(.times$time),]
.funcs$set(as.character(id), func)
return(id)
},
timeToNextEvent = function() {
@@ -46,18 +47,18 @@ TimerCallbacks <- setRefClass(
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())
return(result)
},
executeElapsed = function() {
elapsed <- takeElapsed()
if (length(elapsed) == 0)
return(FALSE)
for (id in elapsed$id) {
thisFunc <- .funcs$remove(as.character(id))
# TODO: Catch exception, and...?

View File

@@ -54,38 +54,6 @@ updateTextInput <- function(session, inputId, label = NULL, value = NULL) {
updateCheckboxInput <- updateTextInput
#' Change the value of a slider input on the client
#'
#' @template update-input
#' @param value The value to set for the input object.
#'
#' @seealso \code{\link{sliderInput}}
#'
#' @examples
#' \dontrun{
#' shinyServer(function(input, output, session) {
#'
#' observe({
#' # We'll use the input$controller variable multiple times, so save it as x
#' # for convenience.
#' x <- input$controller
#'
#' # Similar to number and text. only label and value can be set for slider
#' updateSliderInput(session, "inSlider",
#' label = paste("Slider label", x),
#' value = x)
#'
#' # For sliders that pick out a range, pass in a vector of 2 values.
#' updateSliderInput(session, "inSlider2", value = c(x-1, x+1))
#'
#' # An NA means to not change that value (the low or high one)
#' updateSliderInput(session, "inSlider3", value = c(NA, x+2))
#' })
#' })
#' }
#' @export
updateSliderInput <- updateTextInput
#' Change the value of a date input on the client
#'
#' @template update-input
@@ -118,7 +86,7 @@ updateSliderInput <- updateTextInput
#' }
#' @export
updateDateInput <- function(session, inputId, label = NULL, value = NULL,
min = NULL, max = NULL) {
min = NULL, max = NULL) {
# If value is a date object, convert it to a string with yyyy-mm-dd format
# Same for min and max
@@ -163,8 +131,8 @@ updateDateInput <- function(session, inputId, label = NULL, value = NULL,
#' }
#' @export
updateDateRangeInput <- function(session, inputId, label = NULL,
start = NULL, end = NULL, min = NULL, max = NULL) {
start = NULL, end = NULL, min = NULL,
max = NULL) {
# Make sure start and end are strings, not date objects. This is for
# consistency across different locales.
if (inherits(start, "Date")) start <- format(start, '%Y-%m-%d')
@@ -186,10 +154,12 @@ updateDateRangeInput <- function(session, inputId, label = NULL,
#'
#' @param session The \code{session} object passed to function given to
#' \code{shinyServer}.
#' @param inputId The id of the tabset panel object.
#' @param inputId The id of the \code{tabsetPanel}, \code{navlistPanel},
#' or \code{navbarPage} object.
#' @param selected The name of the tab to make active.
#'
#' @seealso \code{\link{tabsetPanel}}
#' @seealso \code{\link{tabsetPanel}}, \code{\link{navlistPanel}},
#' \code{\link{navbarPage}}
#'
#' @examples
#' \dontrun{
@@ -200,7 +170,7 @@ updateDateRangeInput <- function(session, inputId, label = NULL,
#' x_even <- input$controller %% 2 == 0
#'
#' # Change the selected tab.
#' # Note that the tabsetPanel must have been created with an 'id' argument
#' # Note that the tabset container must have been created with an 'id' argument
#' if (x_even) {
#' updateTabsetPanel(session, "inTabset", selected = "panel2")
#' } else {
@@ -215,6 +185,13 @@ updateTabsetPanel <- function(session, inputId, selected = NULL) {
session$sendInputMessage(inputId, message)
}
#' @rdname updateTabsetPanel
#' @export
updateNavbarPage <- updateTabsetPanel
#' @rdname updateTabsetPanel
#' @export
updateNavlistPanel <- updateTabsetPanel
#' Change the value of a number input on the client
#'
@@ -247,17 +224,108 @@ updateTabsetPanel <- function(session, inputId, selected = NULL) {
updateNumericInput <- function(session, inputId, label = NULL, value = NULL,
min = NULL, max = NULL, step = NULL) {
message <- dropNulls(list(label=label, value=value, min=min, max=max, step=step))
message <- dropNulls(list(
label = label, value = formatNoSci(value),
min = formatNoSci(min), max = formatNoSci(max), step = formatNoSci(step)
))
session$sendInputMessage(inputId, message)
}
#' Change the value of a slider input on the client
#'
#' @template update-input
#' @param value The value to set for the input object.
#' @param min Minimum value.
#' @param max Maximum value.
#' @param step Step size.
#'
#' @seealso \code{\link{sliderInput}}
#'
#' @examples
#' ## Only run this example in interactive R sessions
#' if (interactive()) {
#' shinyApp(
#' ui = fluidPage(
#' sidebarLayout(
#' sidebarPanel(
#' p("The first slider controls the second"),
#' sliderInput("control", "Controller:", min=0, max=20, value=10,
#' step=1),
#' sliderInput("receive", "Receiver:", min=0, max=20, value=10,
#' step=1)
#' ),
#' mainPanel()
#' )
#' ),
#' server = function(input, output, session) {
#' observe({
#' val <- input$control
#' # Control the value, min, max, and step.
#' # Step size is 2 when input value is even; 1 when value is odd.
#' updateSliderInput(session, "receive", value = val,
#' min = floor(val/2), max = val+4, step = (val+1)%%2 + 1)
#' })
#' }
#' )
#' }
#' @export
updateSliderInput <- function(session, inputId, label = NULL, value = NULL,
min = NULL, max = NULL, step = NULL)
{
# Make sure that value, min, max all have the same type, because we need
# special handling for dates and datetimes.
vals <- dropNulls(list(value, min, max))
type <- unique(lapply(vals, function(x) {
if (inherits(x, "Date")) "date"
else if (inherits(x, "POSIXt")) "datetime"
else "number"
}))
if (length(type) > 1) {
stop("Type mismatch for value, min, and max")
}
if ((length(type) == 1) && (type == "date" || type == "datetime")) {
to_ms <- function(x) 1000 * as.numeric(as.POSIXct(x))
if (!is.null(min)) min <- to_ms(min)
if (!is.null(max)) max <- to_ms(max)
if (!is.null(value)) value <- to_ms(value)
}
message <- dropNulls(list(
label = label,
value = formatNoSci(value),
min = formatNoSci(min),
max = formatNoSci(max),
step = formatNoSci(step)
))
session$sendInputMessage(inputId, message)
}
updateInputOptions <- function(session, inputId, label = NULL, choices = NULL,
selected = NULL, inline = FALSE,
type = 'checkbox') {
if (!is.null(choices))
choices <- choicesWithNames(choices)
if (!is.null(selected))
selected <- validateSelected(selected, choices, inputId)
options <- if (!is.null(choices)) {
format(tagList(
generateOptions(inputId, choices, selected, inline, type = type)
))
}
message <- dropNulls(list(label = label, options = options, value = selected))
session$sendInputMessage(inputId, message)
}
#' Change the value of a checkbox group input on the client
#'
#' @template update-input
#' @param choices A named vector or named list of options. For each item, the
#' name will be used as the label, and the value will be used as the value.
#' @param selected A vector or list of options which will be selected.
#' @inheritParams checkboxGroupInput
#'
#' @seealso \code{\link{checkboxGroupInput}}
#'
@@ -283,38 +351,23 @@ updateNumericInput <- function(session, inputId, label = NULL, value = NULL,
#' updateCheckboxGroupInput(session, "inCheckboxGroup2",
#' label = paste("checkboxgroup label", x),
#' choices = cb_options,
#' selected = sprintf("option label %d 2", x)
#' selected = sprintf("option-%d-2", x)
#' )
#' })
#' })
#' }
#' @export
updateCheckboxGroupInput <- function(session, inputId, label = NULL,
choices = NULL, selected = NULL) {
choices <- choicesWithNames(choices)
options <- mapply(choices, names(choices),
SIMPLIFY = FALSE, USE.NAMES = FALSE,
FUN = function(value, name) {
list(value = value,
label = name,
checked = name %in% selected)
}
)
message <- dropNulls(list(label = label, options = options))
session$sendInputMessage(inputId, message)
choices = NULL, selected = NULL,
inline = FALSE) {
updateInputOptions(session, inputId, label, choices, selected, inline)
}
#' Change the value of a radio input on the client
#'
#' @template update-input
#' @param choices A named vector or named list of options. For each item, the
#' name will be used as the label, and the value will be used as the value.
#' @param selected A vector or list of options which will be selected.
#' @inheritParams radioButtons
#'
#' @seealso \code{\link{radioButtons}}
#'
@@ -338,21 +391,24 @@ updateCheckboxGroupInput <- function(session, inputId, label = NULL,
#' updateRadioButtons(session, "inRadio2",
#' label = paste("Radio label", x),
#' choices = r_options,
#' selected = sprintf("option label %d 2", x)
#' selected = sprintf("option-%d-2", x)
#' )
#' })
#' })
#' }
#' @export
updateRadioButtons <- updateCheckboxGroupInput
updateRadioButtons <- function(session, inputId, label = NULL, choices = NULL,
selected = NULL, inline = FALSE) {
# you must select at least one radio button
if (is.null(selected) && !is.null(choices)) selected <- choices[[1]]
updateInputOptions(session, inputId, label, choices, selected, inline, type = 'radio')
}
#' Change the value of a select input on the client
#'
#' @template update-input
#' @param choices A named vector or named list of options. For each item, the
#' name will be used as the label, and the value will be used as the value.
#' @param selected A vector or list of options which will be selected.
#' @inheritParams selectInput
#'
#' @seealso \code{\link{selectInput}}
#'
@@ -379,27 +435,96 @@ updateRadioButtons <- updateCheckboxGroupInput
#' updateSelectInput(session, "inSelect2",
#' label = paste("Select label", x),
#' choices = s_options,
#' selected = sprintf("option label %d 2", x)
#' selected = sprintf("option-%d-2", x)
#' )
#' })
#' })
#' }
#' @export
updateSelectInput <- function(session, inputId, label = NULL, choices = NULL,
selected = NULL) {
choices <- choicesWithNames(choices)
options <- mapply(choices, names(choices),
SIMPLIFY = FALSE, USE.NAMES = FALSE,
FUN = function(value, name) {
list(value = value,
label = name,
selected = name %in% selected)
}
)
message <- dropNulls(list(label = label, options = options))
selected = NULL) {
choices <- if (!is.null(choices)) choicesWithNames(choices)
if (!is.null(selected))
selected <- validateSelected(selected, choices, inputId)
options <- if (!is.null(choices)) selectOptions(choices, selected)
message <- dropNulls(list(label = label, options = options, value = selected))
session$sendInputMessage(inputId, message)
}
#' @rdname updateSelectInput
#' @inheritParams selectizeInput
#' @param server whether to store \code{choices} on the server side, and load
#' the select options dynamically on searching, instead of writing all
#' \code{choices} into the page at once (i.e., only use the client-side
#' version of \pkg{selectize.js})
#' @export
updateSelectizeInput <- function(session, inputId, label = NULL, choices = NULL,
selected = NULL, options = list(),
server = FALSE) {
if (length(options)) {
res <- checkAsIs(options)
cfg <- tags$script(
type = 'application/json',
`data-for` = inputId,
`data-eval` = if (length(res$eval)) HTML(toJSON(res$eval)),
HTML(toJSON(res$options))
)
session$sendInputMessage(inputId, list(config = as.character(cfg)))
}
if (!server) {
return(updateSelectInput(session, inputId, label, choices, selected))
}
value <- unname(selected)
attr(choices, 'selected_value') <- value
message <- dropNulls(list(
label = label,
value = value,
url = session$registerDataObj(inputId, choices, selectizeJSON)
))
session$sendInputMessage(inputId, message)
}
selectizeJSON <- function(data, req) {
query <- parseQueryString(req$QUERY_STRING)
# extract the query variables, conjunction (and/or), search string, maximum options
var <- c(jsonlite::fromJSON(query$field))
cjn <- if (query$conju == 'and') all else any
# all keywords in lower-case, for case-insensitive matching
key <- unique(strsplit(tolower(query$query), '\\s+')[[1]])
if (identical(key, '')) key <- character(0)
mop <- as.numeric(query$maxop)
vfd <- query$value # the value field name
sel <- attr(data, 'selected_value', exact = TRUE)
# convert a single vector to a data frame so it returns {label: , value: }
# later in JSON; other objects return arbitrary JSON {x: , y: , foo: , ...}
data <- if (is.atomic(data)) {
data.frame(label = names(choicesWithNames(data)), value = data,
stringsAsFactors = FALSE)
} else as.data.frame(data, stringsAsFactors = FALSE)
# start searching for keywords in all specified columns
idx <- logical(nrow(data))
if (length(key)) for (v in var) {
matches <- do.call(
cbind,
lapply(key, function(k) {
grepl(k, tolower(as.character(data[[v]])), fixed = TRUE)
})
)
# merge column matches using OR, and match multiple keywords in one column
# using the conjunction setting (AND or OR)
idx <- idx | apply(matches, 1, cjn)
}
# only return the first n rows (n = maximum options in configuration)
idx <- utils::head(if (length(key)) which(idx) else seq_along(idx), mop)
# make sure the selected value is in the data
if (length(sel)) {
i <- stats::na.omit(match(sel, data[, vfd]))
if (length(i)) idx <- sort(utils::head(unique(c(i, idx)), mop))
}
data <- data[idx, ]
res <- toJSON(columnToRowData(data))
httpResponse(200, 'application/json', enc2utf8(res))
}

1124
R/utils.R

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,18 @@
# Shiny
# Shiny
[![Build Status](https://travis-ci.org/rstudio/shiny.svg?branch=master)](https://travis-ci.org/rstudio/shiny)
Shiny is a new package from RStudio that makes it incredibly easy to build interactive web applications with R.
For an introduction and examples, visit the [Shiny homepage](http://www.rstudio.com/shiny/).
For an introduction and examples, visit the [Shiny Dev Center](http://shiny.rstudio.com/).
## Features
* Build useful web applications with only a few lines of code&mdash;no JavaScript required.
* Shiny applications are automatically "live" in the same way that spreadsheets are live. Outputs change instantly as users modify inputs, without requiring a reload of the browser.
* Shiny user interfaces can be built entirely using R, or can be written directly in HTML, CSS, and JavaScript for more flexibility.
* Works in any R environment (Console R, Rgui for Windows or Mac, ESS, StatET, RStudio, etc.)
* Attractive default UI theme based on [Twitter Bootstrap](http://twitter.github.com/bootstrap).
* Works in any R environment (Console R, Rgui for Windows or Mac, ESS, StatET, RStudio, etc.).
* Attractive default UI theme based on [Bootstrap](http://getbootstrap.com/2.3.2/).
* A highly customizable slider widget with built-in support for animation.
* Pre-built output widgets for displaying plots, tables, and printed output of R objects.
* Fast bidirectional communication between the web browser and R using the [httpuv](https://github.com/rstudio/httpuv) package.
@@ -30,15 +32,31 @@ To install the latest development builds directly from GitHub, run this instead:
```r
if (!require("devtools"))
install.packages("devtools")
devtools::install_github("shiny", "rstudio")
devtools::install_github("rstudio/shiny")
```
## Getting Started
To learn more we highly recommend you check out the [Shiny Tutorial](http://rstudio.github.com/shiny/tutorial). The tutorial explains the framework in-depth, walks you through building a simple application, and includes extensive annotated examples.
To learn more we highly recommend you check out the [Shiny Tutorial](http://shiny.rstudio.com/tutorial/). The tutorial explains the framework in-depth, walks you through building a simple application, and includes extensive annotated examples.
We hope you enjoy using Shiny. If you have general questions about using Shiny, please use the Shiny [mailing list](https://groups.google.com/forum/#!forum/shiny-discuss). For bug reports, please use the [issue tracker](https://github.com/rstudio/shiny/issues).
## Bootstrap 3 migration
Shiny versions 0.10.2.2 and below used the Bootstrap 2 web framework. After 0.10.2.2, Shiny switched to Bootstrap 3. For most users, the upgrade should be seamless. However, if you have have customized your HTML-generating code to use features specific to Bootstrap 2, you may need to update your code to work with Bootstrap 3.
If you do not wish to update your code at this time, you can use the [shinybootstrap2](https://github.com/rstudio/shinybootstrap2) package for backward compatibility.
If you prefer to install an older version of Shiny, you can do it using the devtools package:
```R
devtools::install_version("shiny", version = "0.10.2.2")
```
## Development notes
The Javascript code in Shiny is minified using tools that run on Node.js. See the tools/ directory for more information.
## License
The shiny package is licensed under the GPLv3. See these files in the inst directory for additional details:

0
cran-comments.md Normal file
View File

View File

@@ -1,678 +0,0 @@
The shiny package is licensed to you under the GPLv3, the terms of
which are included below. The markdown pacakge includes other open
source software whose license terms can be found in the file NOTICE.
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@@ -1,297 +0,0 @@
The shiny package inludes other open source software components. The following
is a list of these components (full copies of the license agreements used by
these components are included below):
- jQuery
- Bootstrap
- bootstrap-datepicker, from https://github.com/eternicode/bootstrap-datepicker
- jslider
- DataTables
jQuery License
----------------------------------------------------------------------
Copyright (c) 2012 jQuery Foundation and other contributors,
http://jquery.com/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Bootstrap and bootstrap-datepicker License
----------------------------------------------------------------------
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
jslider License
----------------------------------------------------------------------
The MIT License (MIT)
Copyright (c) 2012 Egor Khmelev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
DataTables License
----------------------------------------------------------------------
Copyright (c) 2008-2010, Allan Jardine
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Allan Jardine nor SpryMedia UK may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,7 @@
Title: Hello Shiny!
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
DisplayMode: Showcase
Tags: getting-started
Type: Shiny

View File

@@ -0,0 +1,4 @@
This small Shiny application demonstrates Shiny's automatic UI updates. Move
the *Number of bins* slider and notice how the `renderPlot` expression is
automatically re-evaluated when its dependant, `input$bins`, changes,
causing a histogram with a new number of bins to be rendered.

View File

@@ -0,0 +1,6 @@
name: 01_hello
account: admin
server: localhost
bundleId: 1
url: http://localhost:3939/admin/01_hello/
when: 1436550957.65385

View File

@@ -1,20 +1,21 @@
library(shiny)
# Define server logic required to generate and plot a random distribution
# Define server logic required to draw a histogram
shinyServer(function(input, output) {
# Expression that generates a plot of the distribution. The expression
# is wrapped in a call to renderPlot to indicate that:
# Expression that generates a histogram. The expression is
# wrapped in a call to renderPlot to indicate that:
#
# 1) It is "reactive" and therefore should be automatically
# 1) It is "reactive" and therefore should be automatically
# re-executed when inputs change
# 2) Its output type is a plot
#
# 2) Its output type is a plot
output$distPlot <- renderPlot({
# generate an rnorm distribution and plot it
dist <- rnorm(input$obs)
hist(dist)
x <- faithful[, 2] # Old Faithful Geyser data
bins <- seq(min(x), max(x), length.out = input$bins + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
})

View File

@@ -1,22 +1,24 @@
library(shiny)
# Define UI for application that plots random distributions
shinyUI(pageWithSidebar(
# Define UI for application that draws a histogram
shinyUI(fluidPage(
# Application title
headerPanel("Hello Shiny!"),
# Sidebar with a slider input for number of observations
sidebarPanel(
sliderInput("obs",
"Number of observations:",
min = 1,
max = 1000,
value = 500)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
titlePanel("Hello Shiny!"),
# Sidebar with a slider input for the number of bins
sidebarLayout(
sidebarPanel(
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
))

View File

@@ -0,0 +1,8 @@
Title: Shiny Text
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
DisplayMode: Showcase
Tags: getting-started
Type: Shiny

View File

@@ -0,0 +1 @@
This example demonstrates output of raw text from R using the `renderPrint` function in `server.R` and the `verbatimTextOutput` function in `ui.R`. In this case, a textual summary of the data is shown using R's built-in `summary` function.

View File

@@ -1,7 +1,8 @@
library(shiny)
library(datasets)
# Define server logic required to summarize and view the selected dataset
# Define server logic required to summarize and view the selected
# dataset
shinyServer(function(input, output) {
# Return the requested dataset

View File

@@ -1,25 +1,27 @@
library(shiny)
# Define UI for dataset viewer application
shinyUI(pageWithSidebar(
shinyUI(fluidPage(
# Application title
headerPanel("Shiny Text"),
titlePanel("Shiny Text"),
# Sidebar with controls to select a dataset and specify the number
# of observations to view
sidebarPanel(
selectInput("dataset", "Choose a dataset:",
choices = c("rock", "pressure", "cars")),
# Sidebar with controls to select a dataset and specify the
# number of observations to view
sidebarLayout(
sidebarPanel(
selectInput("dataset", "Choose a dataset:",
choices = c("rock", "pressure", "cars")),
numericInput("obs", "Number of observations to view:", 10)
),
numericInput("obs", "Number of observations to view:", 10)
),
# Show a summary of the dataset and an HTML table with the requested
# number of observations
mainPanel(
verbatimTextOutput("summary"),
tableOutput("view")
# Show a summary of the dataset and an HTML table with the
# requested number of observations
mainPanel(
verbatimTextOutput("summary"),
tableOutput("view")
)
)
))

View File

@@ -0,0 +1,7 @@
Title: Reactivity
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
DisplayMode: Showcase
Tags: getting-started
Type: Shiny

View File

@@ -0,0 +1,5 @@
This example demonstrates a core feature of Shiny: **reactivity**. In `server.R`, a reactive called `datasetInput` is declared.
Notice that the reactive expression depends on the input expression `input$dataset`, and that it's used by both the output expression `output$summary` and `output$view`. Try changing the dataset (using *Choose a dataset*) while looking at the reactive and then at the outputs; you will see first the reactive and then its dependencies flash.
Notice also that the reactive expression doesn't just update whenever anything changes--only the inputs it depends on will trigger an update. Change the "Caption" field and notice how only the `output$caption` expression is re-evaluated; the reactive and its dependents are left alone.

View File

@@ -1,17 +1,16 @@
library(shiny)
library(datasets)
# Define server logic required to summarize and view the selected dataset
# Define server logic required to summarize and view the selected
# dataset
shinyServer(function(input, output) {
# By declaring databaseInput as a reactive expression we ensure that:
# By declaring datasetInput as a reactive expression we ensure
# that:
#
# 1) It is only called when the inputs it depends on changes
# 2) The computation and result are shared by all the callers (it
# only executes a single time)
# 3) When the inputs change and the expression is re-executed, the
# new result is compared to the previous result; if the two are
# identical, then the callers are not notified
# 2) The computation and result are shared by all the callers
# (it only executes a single time)
#
datasetInput <- reactive({
switch(input$dataset,
@@ -20,30 +19,34 @@ shinyServer(function(input, output) {
"cars" = cars)
})
# The output$caption is computed based on a reactive expression that
# returns input$caption. When the user changes the "caption" field:
# The output$caption is computed based on a reactive expression
# that returns input$caption. When the user changes the
# "caption" field:
#
# 1) This function is automatically called to recompute the output
# 2) The new caption is pushed back to the browser for re-display
# 1) This function is automatically called to recompute the
# output
# 2) The new caption is pushed back to the browser for
# re-display
#
# Note that because the data-oriented reactive expressions below don't
# depend on input$caption, those expressions are NOT called when
# input$caption changes.
# Note that because the data-oriented reactive expressions
# below don't depend on input$caption, those expressions are
# NOT called when input$caption changes.
output$caption <- renderText({
input$caption
})
# The output$summary depends on the datasetInput reactive expression,
# so will be re-executed whenever datasetInput is re-executed
# The output$summary depends on the datasetInput reactive
# expression, so will be re-executed whenever datasetInput is
# invalidated
# (i.e. whenever the input$dataset changes)
output$summary <- renderPrint({
dataset <- datasetInput()
summary(dataset)
})
# The output$view depends on both the databaseInput reactive expression
# and input$obs, so will be re-executed whenever input$dataset or
# input$obs is changed.
# The output$view depends on both the databaseInput reactive
# expression and input$obs, so will be re-executed whenever
# input$dataset or input$obs is changed.
output$view <- renderTable({
head(datasetInput(), n = input$obs)
})

View File

@@ -1,32 +1,34 @@
library(shiny)
# Define UI for dataset viewer application
shinyUI(pageWithSidebar(
shinyUI(fluidPage(
# Application title
headerPanel("Reactivity"),
titlePanel("Reactivity"),
# Sidebar with controls to provide a caption, select a dataset, and
# specify the number of observations to view. Note that changes made
# to the caption in the textInput control are updated in the output
# area immediately as you type
sidebarPanel(
textInput("caption", "Caption:", "Data Summary"),
# Sidebar with controls to provide a caption, select a dataset,
# and specify the number of observations to view. Note that
# changes made to the caption in the textInput control are
# updated in the output area immediately as you type
sidebarLayout(
sidebarPanel(
textInput("caption", "Caption:", "Data Summary"),
selectInput("dataset", "Choose a dataset:",
choices = c("rock", "pressure", "cars")),
numericInput("obs", "Number of observations to view:", 10)
),
selectInput("dataset", "Choose a dataset:",
choices = c("rock", "pressure", "cars")),
numericInput("obs", "Number of observations to view:", 10)
),
# Show the caption, a summary of the dataset and an HTML table with
# the requested number of observations
mainPanel(
h3(textOutput("caption")),
verbatimTextOutput("summary"),
tableOutput("view")
# Show the caption, a summary of the dataset and an HTML
# table with the requested number of observations
mainPanel(
h3(textOutput("caption", container = span)),
verbatimTextOutput("summary"),
tableOutput("view")
)
)
))

View File

@@ -0,0 +1,7 @@
Title: Miles Per Gallon
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
DisplayMode: Showcase
Tags: getting-started
Type: Shiny

View File

@@ -0,0 +1,4 @@
This example demonstrates the following concepts:
* **Global variables**: The `mpgData` variable is declared outside the `shinyServer` function. This makes it available anywhere inside `shinyServer`. The code in `server.R` outside `shinyServer` is only run once when the app starts up, so it can't contain user input.
* **Reactive expressions**: `formulaText` is a reactive expression. Note how it re-evaluates when the Variable field is changed, but not when the Show Outliers box is ticked.

View File

@@ -1,31 +1,33 @@
library(shiny)
library(datasets)
# We tweak the "am" field to have nicer factor labels. Since this doesn't
# rely on any user inputs we can do this once at startup and then use the
# value throughout the lifetime of the application
# We tweak the "am" field to have nicer factor labels. Since
# this doesn't rely on any user inputs we can do this once at
# startup and then use the value throughout the lifetime of the
# application
mpgData <- mtcars
mpgData$am <- factor(mpgData$am, labels = c("Automatic", "Manual"))
# Define server logic required to plot various variables against mpg
# Define server logic required to plot various variables against
# mpg
shinyServer(function(input, output) {
# Compute the forumla text in a reactive expression since it is
# Compute the formula text in a reactive expression since it is
# shared by the output$caption and output$mpgPlot functions
formulaText <- reactive({
paste("mpg ~", input$variable)
})
# Return the formula text for printing as a caption
output$caption <- renderText({
formulaText()
})
# Generate a plot of the requested variable against mpg and only
# include outliers if requested
# Generate a plot of the requested variable against mpg and
# only include outliers if requested
output$mpgPlot <- renderPlot({
boxplot(as.formula(formulaText()),
boxplot(as.formula(formulaText()),
data = mpgData,
outline = input$outliers)
})

View File

@@ -1,26 +1,29 @@
library(shiny)
# Define UI for miles per gallon application
shinyUI(pageWithSidebar(
shinyUI(fluidPage(
# Application title
headerPanel("Miles Per Gallon"),
titlePanel("Miles Per Gallon"),
# Sidebar with controls to select the variable to plot against mpg
# and to specify whether outliers should be included
sidebarPanel(
selectInput("variable", "Variable:",
c("Cylinders" = "cyl",
"Transmission" = "am",
"Gears" = "gear")),
checkboxInput("outliers", "Show outliers", FALSE)
),
# Sidebar with controls to select the variable to plot against
# mpg and to specify whether outliers should be included
sidebarLayout(
sidebarPanel(
selectInput("variable", "Variable:",
c("Cylinders" = "cyl",
"Transmission" = "am",
"Gears" = "gear")),
# Show the caption and plot of the requested variable against mpg
mainPanel(
h3(textOutput("caption")),
checkboxInput("outliers", "Show outliers", FALSE)
),
plotOutput("mpgPlot")
# Show the caption and plot of the requested variable against
# mpg
mainPanel(
h3(textOutput("caption")),
plotOutput("mpgPlot")
)
)
))

View File

@@ -0,0 +1,7 @@
Title: Sliders
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
DisplayMode: Showcase
Tags: getting-started
Type: Shiny

View File

@@ -0,0 +1,3 @@
This example demonstrates Shiny's versatile `sliderInput` widget.
Slider inputs can be used to select single values, to select a continuous range of values, and even to animate over a range.

View File

@@ -3,7 +3,8 @@ library(shiny)
# Define server logic for slider examples
shinyServer(function(input, output) {
# Reactive expression to compose a data frame containing all of the values
# Reactive expression to compose a data frame containing all of
# the values
sliderValues <- reactive({
# Compose data frame

View File

@@ -1,37 +1,43 @@
library(shiny)
# Define UI for slider demo application
shinyUI(pageWithSidebar(
shinyUI(fluidPage(
# Application title
headerPanel("Sliders"),
# Sidebar with sliders that demonstrate various available options
sidebarPanel(
# Simple integer interval
sliderInput("integer", "Integer:",
min=0, max=1000, value=500),
# Decimal interval with step value
sliderInput("decimal", "Decimal:",
min = 0, max = 1, value = 0.5, step= 0.1),
# Specification of range within an interval
sliderInput("range", "Range:",
min = 1, max = 1000, value = c(200,500)),
# Provide a custom currency format for value display, with basic animation
sliderInput("format", "Custom Format:",
min = 0, max = 10000, value = 0, step = 2500,
format="$#,##0", locale="us", animate=TRUE),
# Animation with custom interval (in ms) to control speed, plus looping
sliderInput("animation", "Looping Animation:", 1, 2000, 1, step = 10,
animate=animationOptions(interval=300, loop=TRUE))
),
# Show a table summarizing the values entered
mainPanel(
tableOutput("values")
titlePanel("Sliders"),
# Sidebar with sliders that demonstrate various available
# options
sidebarLayout(
sidebarPanel(
# Simple integer interval
sliderInput("integer", "Integer:",
min=0, max=1000, value=500),
# Decimal interval with step value
sliderInput("decimal", "Decimal:",
min = 0, max = 1, value = 0.5, step= 0.1),
# Specification of range within an interval
sliderInput("range", "Range:",
min = 1, max = 1000, value = c(200,500)),
# Provide a custom currency format for value display,
# with basic animation
sliderInput("format", "Custom Format:",
min = 0, max = 10000, value = 0, step = 2500,
pre = "$", sep = ",", animate=TRUE),
# Animation with custom interval (in ms) to control speed,
# plus looping
sliderInput("animation", "Looping Animation:", 1, 2000, 1,
step = 10, animate=
animationOptions(interval=300, loop=TRUE))
),
# Show a table summarizing the values entered
mainPanel(
tableOutput("values")
)
)
))
))

View File

@@ -0,0 +1,7 @@
Title: Tabsets
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
DisplayMode: Showcase
Tags: getting-started
Type: Shiny

View File

@@ -0,0 +1,9 @@
This example demonstrates the `tabsetPanel` and `tabPanel` widgets.
Notice that outputs that are not visible are not re-evaluated until they become visible. Try this:
1. Scroll to the bottom of `server.R`
2. Change the number of observations, and observe that only `output$plot` is evaluated.
3. Click the Summary tab, and observe that `output$summary` is evaluated.
4. Change the number of observations again, and observe that now only `output$summary` is evaluated.

View File

@@ -3,9 +3,10 @@ library(shiny)
# Define server logic for random distribution application
shinyServer(function(input, output) {
# Reactive expression to generate the requested distribution. This is
# called whenever the inputs change. The output functions defined
# below then all use the value computed from this expression
# Reactive expression to generate the requested distribution.
# This is called whenever the inputs change. The output
# functions defined below then all use the value computed from
# this expression
data <- reactive({
dist <- switch(input$dist,
norm = rnorm,
@@ -17,10 +18,11 @@ shinyServer(function(input, output) {
dist(input$n)
})
# Generate a plot of the data. Also uses the inputs to build the
# plot label. Note that the dependencies on both the inputs and
# the data reactive expression are both tracked, and all expressions
# are called in the sequence implied by the dependency graph
# Generate a plot of the data. Also uses the inputs to build
# the plot label. Note that the dependencies on both the inputs
# and the data reactive expression are both tracked, and
# all expressions are called in the sequence implied by the
# dependency graph
output$plot <- renderPlot({
dist <- input$dist
n <- input$n

View File

@@ -1,36 +1,38 @@
library(shiny)
# Define UI for random distribution application
shinyUI(pageWithSidebar(
shinyUI(fluidPage(
# Application title
headerPanel("Tabsets"),
titlePanel("Tabsets"),
# Sidebar with controls to select the random distribution type
# and number of observations to generate. Note the use of the br()
# element to introduce extra vertical spacing
sidebarPanel(
radioButtons("dist", "Distribution type:",
c("Normal" = "norm",
"Uniform" = "unif",
"Log-normal" = "lnorm",
"Exponential" = "exp")),
br(),
# and number of observations to generate. Note the use of the
# br() element to introduce extra vertical spacing
sidebarLayout(
sidebarPanel(
radioButtons("dist", "Distribution type:",
c("Normal" = "norm",
"Uniform" = "unif",
"Log-normal" = "lnorm",
"Exponential" = "exp")),
br(),
sliderInput("n",
"Number of observations:",
value = 500,
min = 1,
max = 1000)
),
sliderInput("n",
"Number of observations:",
value = 500,
min = 1,
max = 1000)
),
# Show a tabset that includes a plot, summary, and table view
# of the generated distribution
mainPanel(
tabsetPanel(
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
# Show a tabset that includes a plot, summary, and table view
# of the generated distribution
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
)
)
)
))

View File

@@ -0,0 +1,7 @@
Title: Widgets
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
DisplayMode: Showcase
Tags: getting-started
Type: Shiny

View File

@@ -0,0 +1 @@
This example demonstrates some additional widgets included in Shiny, such as `helpText` and `submitButton`. The latter is used to delay rendering output until the user explicitly requests it.

View File

@@ -1,7 +1,8 @@
library(shiny)
library(datasets)
# Define server logic required to summarize and view the selected dataset
# Define server logic required to summarize and view the
# selected dataset
shinyServer(function(input, output) {
# Return the requested dataset

View File

@@ -1,39 +1,43 @@
library(shiny)
# Define UI for dataset viewer application
shinyUI(pageWithSidebar(
shinyUI(fluidPage(
# Application title.
headerPanel("More Widgets"),
titlePanel("More Widgets"),
# Sidebar with controls to select a dataset and specify the number
# of observations to view. The helpText function is also used to
# include clarifying text. Most notably, the inclusion of a
# submitButton defers the rendering of output until the user
# explicitly clicks the button (rather than doing it immediately
# when inputs change). This is useful if the computations required
# to render output are inordinately time-consuming.
sidebarPanel(
selectInput("dataset", "Choose a dataset:",
choices = c("rock", "pressure", "cars")),
# Sidebar with controls to select a dataset and specify the
# number of observations to view. The helpText function is
# also used to include clarifying text. Most notably, the
# inclusion of a submitButton defers the rendering of output
# until the user explicitly clicks the button (rather than
# doing it immediately when inputs change). This is useful if
# the computations required to render output are inordinately
# time-consuming.
sidebarLayout(
sidebarPanel(
selectInput("dataset", "Choose a dataset:",
choices = c("rock", "pressure", "cars")),
numericInput("obs", "Number of observations to view:", 10),
helpText("Note: while the data view will show only the specified",
"number of observations, the summary will still be based",
"on the full dataset."),
submitButton("Update View")
),
numericInput("obs", "Number of observations to view:", 10),
helpText("Note: while the data view will show only the specified",
"number of observations, the summary will still be based",
"on the full dataset."),
submitButton("Update View")
),
# Show a summary of the dataset and an HTML table with the requested
# number of observations. Note the use of the h4 function to provide
# an additional header above each output section.
mainPanel(
h4("Summary"),
verbatimTextOutput("summary"),
h4("Observations"),
tableOutput("view")
# Show a summary of the dataset and an HTML table with the
# requested number of observations. Note the use of the h4
# function to provide an additional header above each output
# section.
mainPanel(
h4("Summary"),
verbatimTextOutput("summary"),
h4("Observations"),
tableOutput("view")
)
)
))
))

View File

@@ -0,0 +1,7 @@
Title: Custom HTML UI
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
DisplayMode: Showcase
Tags: getting-started
Type: Shiny

View File

@@ -0,0 +1,4 @@
Normally we use the built-in functions, such as `textInput()`, to generate
the HTML UI in the R script `ui.R`. Actually **shiny** also works with a
custom HTML page `www/index.html`. See [the
tutorial](http://rstudio.github.io/shiny/tutorial/#html-ui) for more details.

View File

@@ -0,0 +1,7 @@
Title: File Upload
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
DisplayMode: Showcase
Tags: getting-started
Type: Shiny

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