Compare commits

...

275 Commits

Author SHA1 Message Date
Barret Schloerke
2acaea1444 Add debug statements 2020-10-14 16:05:27 -04:00
Barret Schloerke
1120cfdfd7 Default to list(), not NULL 2020-10-14 16:05:20 -04:00
Winston Chang
d95560db09 Merge pull request #3085 from rstudio/carson/feature/restyle 2020-10-14 10:17:51 -05:00
Winston Chang
98f64df738 Dependency fixes 2020-10-14 10:06:42 -05:00
Winston Chang
8634e372da bs_dependency_dynamic -> bs_dependency_defer 2020-10-14 09:42:16 -05:00
Winston Chang
cbda7633e0 Update MockShinySession 2020-10-13 16:00:15 -05:00
Winston Chang
8f00cf50ca Fix typo 2020-10-13 15:57:52 -05:00
Winston Chang
acca28075b Merge branch 'master' into carson/feature/restyle
Also rebuild shiny.js
2020-10-13 15:56:53 -05:00
Winston Chang
9a563463dd Add namespacing for bs_dependency() 2020-10-13 15:32:00 -05:00
Winston Chang
1ede94b09e Remove registerThemeDependency from pkgdown 2020-10-13 15:30:56 -05:00
Winston Chang
7f41a54c4e Move bootstraplib to Imports 2020-10-13 14:49:51 -05:00
Winston Chang
6cfab79ce9 Make setCurrentTheme() a ShinySession method 2020-10-13 14:47:40 -05:00
Carson Sievert
f33b3c7eef Update R/bootstrap.R 2020-10-13 14:15:12 -05:00
Carson
93d78ae2b0 prevent caching on restyle and account for fact that href may include hostname 2020-10-13 12:37:02 -05:00
Winston Chang
c498b02289 textAreaInput() doesn't work as expected for relative width (#2049)
Squashed commit of the following:

commit a823dd5d7da6fafba69f783e112d71d9dcd09c5f
Author: Winston Chang <winston@stdout.org>
Date:   Mon Oct 12 12:59:41 2020 -0500

    Remove trailing whitespace

commit ae55b519fb0f7d97f559e2f487063366926aa41d
Author: Winston Chang <winston@stdout.org>
Date:   Mon Oct 12 12:52:04 2020 -0500

    Move NEWS item to correct location

commit aa89abc247be1bf5cdf093ff7fe7c51711821438
Merge: ee98773f a1ff7652
Author: Winston Chang <winston@stdout.org>
Date:   Mon Oct 12 12:47:21 2020 -0500

    Merge branch 'master' into shrektan-textarea-style

commit ee98773f1d
Author: shrektan <shrektan@126.com>
Date:   Sat Aug 24 10:35:23 2019 +0800

    correct the NEWS entry

commit b468d8f013
Author: shrektan <shrektan@126.com>
Date:   Sat Aug 24 10:32:52 2019 +0800

    the width of textarea should be specified in the parent div.

commit 5abdcf9260
Merge: 03079f0a b07e553b
Author: shrektan <shrektan@126.com>
Date:   Sat Aug 24 09:54:27 2019 +0800

    resolve conflicts

    Merge remote-tracking branch 'origin/master' into textarea-style

    # Conflicts:
    #	R/input-textarea.R

commit 03079f0a14
Author: shrektan <shrektan@126.com>
Date:   Mon May 7 16:08:05 2018 +0800

    Fixed a bug that `textAreaInput()` doesn't work as expected for relative `width`.
2020-10-12 13:01:44 -05:00
Winston Chang
30b62e6f18 Update bootstrap dependency code 2020-10-09 17:57:50 -05:00
Barret Schloerke
ec18ef651b Add missing space for html lang (#3093)
Followup from https://github.com/rstudio/shiny/pull/3087
2020-10-08 11:02:55 -04:00
Joe Cheng
aad23686fa Bump version number 2020-10-07 16:43:28 -07:00
Joe Cheng
1c85ecd7c0 Bump development version 2020-10-07 16:20:32 -07:00
Winston Chang
a1ff765235 Merge pull request #3055 from rstudio/joe/bugfix/freeze-invalidation 2020-10-07 17:36:16 -05:00
Hadley Wickham
a30ba9226d Implement reactiveConsole() (#3092)
* Implement reactiveConsole(). Fixes #2518

* Also includes makeReactiveBinding tweaks
  * use `reactiveConsole()` to provide a nicer example
  * simplified the implementation using `reactiveVal()`
  * remove from documentation indexes since you probably don't want to be promoting this function
2020-10-07 15:37:14 -05:00
Joe Cheng
980a1e53a7 tabsetPanel binding: unconditionally trigger change on receiveMessage
This brings it into line with all of the other input bindings.
The only exception is sliderInput, which has a more complicated
codepath that goes out of its way to force the slider, for its
own reasons; I didn't change the slider for fear of breaking
something, and it also doesn't exhibit the problem I'm here to
fix (next paragraph).

The goal is to ensure that if forgetLastInput is called on an
input, and then that input receives a message (updateXXXInput)
to update its value, BUT the new value is the SAME as its
existing value, that the input binding still acts like something
changed. This is because we need the id/value to go through
the InputSender code path, and alert the server if a previously
frozen input is now thawed.
2020-10-06 14:30:21 -07:00
Joe Cheng
00092cd2a8 NEWS 2020-10-06 14:29:29 -07:00
Joe Cheng
53ddb54936 Forgot to actually force invalidation for freezeReactiveValue(input) 2020-10-06 14:28:50 -07:00
Joe Cheng
ea1e307a51 Preserve existing (CRAN) behavior of freezeReactiveVal/freezeReactiveValues(non-input), but warn
We don't think anyone is using the freeze functions in the ways
that we are deprecating, if so they should contact us via the
link provided.

If it turns out nobody complains, we can remove the problematic
functions. If people complain, then we'll find out what they're
using them for and we can fix them properly.
2020-10-06 14:28:49 -07:00
Joe Cheng
17bc1e2e06 Force invalidation on freeze 2020-10-06 14:28:49 -07:00
Joe Cheng
ed8f3b730b Address ("fix" is too strong a word) #1791, #2946: freeze/thaw
1. freezeReactiveValue(input, "x") is called, inside a renderUI
   or in an observer that then calls updateXXXInput
2. Some reactive output tries to access input$x, this takes a
   reactive dependency but throws a (silent) error
3. When the flush cycle ends, it automatically thaws

What's *supposed* to happen next is the client receives the new
UI or updateXXXInput message, which causes input$x to change,
which causes the reactive output to invalidate and re-run, this
time without input$x being frozen.

This works, except when the renderUI or updateXXXInput just so
happens to set input$x to the same value it already is. In this
case, the client would detect the duplicate value and not send
it to the server. Therefore, the reactive output would not be
invalidated, and effectively be "stalled" until the next time it
is invalidated for some other reason.

With this change, freezeReactiveValue(input, "x") has a new side
effect, which is telling the client that the very next update to
input$x should not undergo duplicate checking.
2020-10-06 14:28:49 -07:00
Carson
0e109d5237 shiny.css should also be using bs_runtime_dependencies() 2020-10-05 16:21:14 -05:00
Winston Chang
f672226a3d Merge pull request #3087 from rstudio/jooyoungseo-lang-a11y 2020-10-05 15:42:26 -05:00
Carson
481dccd085 Don't export setCurrentTheme() (just provide it as a public session method) 2020-10-05 15:21:59 -05:00
Barret Schloerke
9612f1c3c8 Use a for loop over an lapply to get better error reporting 2020-10-05 15:56:27 -04:00
Barret Schloerke
9e1e5f61a3 Use inline template logic 2020-10-05 15:48:51 -04:00
Barret Schloerke
99a566f473 Tell htmltools that the template is a complete template 2020-10-05 15:17:27 -04:00
Barret Schloerke
1012307467 Make sure lang is set in helper method 2020-10-05 15:16:57 -04:00
Barret Schloerke
b729f45eaf Add missing assignment from merge w/ master 2020-10-05 14:36:11 -04:00
Barret Schloerke
cab799e6ee Add missing close bracket 2020-10-05 14:34:51 -04:00
Carson
a06322d155 No need to capture options since the options are set at render-time 2020-10-05 13:23:59 -05:00
Barret Schloerke
d836cb2a2c Use helper function to cleanly create <html> start tag given the lang val 2020-10-05 12:14:05 -04:00
Barret Schloerke
2249c7a28a Use @inheritParams bootstrapPage to inherit lang definition 2020-10-05 11:58:21 -04:00
Barret Schloerke
0d0422c0a7 Use lang <- getLang(ui) and ui <- setLang(ui, lang) methods 2020-10-05 11:57:17 -04:00
Barret Schloerke
5ea556ee77 Fix docs bug 2020-10-05 11:50:16 -04:00
Barret Schloerke
a34496663b Merge branch 'lang-a11y' of https://github.com/jooyoungseo/shiny into jooyoungseo-lang-a11y 2020-10-05 11:48:00 -04:00
Carson
abeaa71d8d wip generalized real-time theming via setCurrentTheme() 2020-10-02 17:32:57 -05:00
Carson
281a427718 Allow Shiny.renderDependencies() to re-render stylesheets, if requested
Also, make getCurrentTheme() aware of the reactive theme set by bootstraplib::bs_themer()
2020-10-02 11:13:19 -05:00
Carson Sievert
03ab966cdc Make shiny.css bootstraplib aware; use jquerylib (#3060)
* Sassify shiny.css (& make it themable); gut json2 dependency (was there for IE8 support)

* Always serve a compressed bundle; remove shiny.css

* Use getCurrentTheme() and make sure shinyDependencies is a function

* Make sure we have sass/rprojroot before running checkBuilt.sh

* Need repos set

* Compare against bleeding edge of sass

* Perform built check with testthat (copying the approach taken for pkgdown checks)

* Update tests/testthat/test-built-files.R

Co-authored-by: Winston Chang <winston@stdout.org>

Co-authored-by: Winston Chang <winston@stdout.org>
2020-10-02 10:59:59 -05:00
Winston Chang
3dcb810346 Merge pull request #3083 from rstudio/is-bs-theme 2020-10-01 14:17:18 -05:00
Carson
d6eef8b3e1 Add getCurrentTheme to pkgdown 2020-10-01 13:47:59 -05:00
Carson
a770f1cbf2 yarn build 2020-10-01 13:40:50 -05:00
Carson
a5687df9b4 make sure is_bs_theme() is available 2020-10-01 13:33:49 -05:00
Carson Sievert
202881cbbd Localized bootstraplib themes (#3062)
* Get rid of the bootstraplib option and simply use bootstraplib when a theme is active

* Restore previous bootstraplib theme when exiting a file/dir based runApp

* wip use latest htmltools+bootstraplib to sketch out local theme API

* Don't do anything with bootstraplib's global state and make sure bs_theme is an expected value

* typo

* better docs

* bugfix

* Use the new, more general, tagFunction() instead

* Set the theme object as a part of the page layout (instead of in shinyApp())

* rollback the structural changes to selectizeIt() to avoid breaking code that makes assumptions about the return value of selectInput()

* set shinyOption() in bootstrapLib(), not bootstrapPage()

* Add a helper for checking whether theme is a bs_theme

* Make theme a required arg in bootstrapSass

* Have bootstrapLib() call shinyOption() at render-time, and document why it works

* Have bootstrapPage() always place bootstrapLib(theme) at the top of the tagList()

* Only set shinyOption() when an application is running at render-time (otherwise; throw a warning)

* code review

* Export a new getCurrentTheme() for Shiny developers to access the theme's Sass code

* bump version
2020-10-01 13:19:18 -05:00
Winston Chang
24ac3b9d8b Reogranize shinyOptions documentation 2020-09-30 15:55:27 -05:00
Winston Chang
47c1fb88b9 Merge pull request #3080 from rstudio/wch-shinyoptions-session 2020-09-29 10:54:14 -05:00
Winston Chang
170b143b17 Document cache option, remove bootstraplib 2020-09-29 10:44:49 -05:00
Winston Chang
3854b49c35 Document shiny.autoload.r option 2020-09-29 10:37:08 -05:00
Winston Chang
bae4f604b5 Update NEWS 2020-09-29 10:34:43 -05:00
Winston Chang
36f32e14d3 Add shinyOptions scoping tests 2020-09-28 19:15:20 -05:00
Winston Chang
9e521e6927 Add missing paren 2020-09-28 17:44:05 -05:00
Winston Chang
4176f541fc Add test for captureAppOptions()
Co-authored-by: Barret Schloerke <barret@rstudio.com>
2020-09-28 17:40:34 -05:00
Winston Chang
18f2afbf85 Fix missing itemize 2020-09-28 16:34:16 -05:00
Winston Chang
f9a94d9758 Merge pull request #3075 from rstudio/wch-rm-ie-upload 2020-09-28 16:03:51 -05:00
Winston Chang
d1e672e3e3 Remove $saveFileUrl method 2020-09-28 16:03:19 -05:00
Winston Chang
202b924e63 Separate docs for options and shinyOptions 2020-09-28 10:43:08 -05:00
Winston Chang
4c3342aa99 Get rid of .globals$testMode 2020-09-25 14:44:59 -05:00
Winston Chang
b1e5dd1d1d Remove .globals 2020-09-25 14:16:10 -05:00
Winston Chang
d43ebfbdb9 Remove withLocalOptions 2020-09-25 14:15:34 -05:00
Winston Chang
cfadd8307b Copy app and session-level shinyOptions at instantiation time 2020-09-25 14:06:36 -05:00
Winston Chang
fa6cf9832d Add session-level shinyOptions 2020-09-24 20:55:17 -05:00
Winston Chang
0075b0da33 Annotate runApp and use initCurrentAppState() 2020-09-24 20:35:03 -05:00
Winston Chang
59c6367cb5 Use getCurrentAppState() for shinyOptions instead of .global$options 2020-09-24 20:33:35 -05:00
Winston Chang
194323a9ee Removed useless option setting
This option is immediately cleared by the next line of code.
2020-09-24 19:52:10 -05:00
Winston Chang
1ca437e4ee Add tests for captureAppOptions 2020-09-24 19:48:10 -05:00
Winston Chang
77e43b9f50 Rename consumeAppOptions to captureAppOptions and provide example 2020-09-24 19:47:48 -05:00
Winston Chang
a23f4b0224 Merge pull request #3078 from rstudio/wch-rename1 2020-09-24 19:03:23 -05:00
Winston Chang
0541c90980 Re-document 2020-09-24 14:53:38 -05:00
Winston Chang
b73a263de8 Rename server-orig.R back to server.R 2020-09-24 14:47:01 -05:00
Winston Chang
d7ffee68cf Merge branch 'wch-rename' into wch-rename1 2020-09-24 14:46:30 -05:00
Winston Chang
89cd42b904 Create server-resource-paths.R from server.R 2020-09-24 14:45:37 -05:00
Winston Chang
404185eb8c Merge branch 'wch-rename' into wch-rename1 2020-09-24 14:44:47 -05:00
Winston Chang
8c29a81b12 Create runapp.R from server.R 2020-09-24 14:43:46 -05:00
Winston Chang
9b42c6c379 Merge branch 'wch-rename' into wch-rename1 2020-09-24 14:42:48 -05:00
Winston Chang
03c2dd9e4b Rename server.R server-orig.R 2020-09-24 14:40:09 -05:00
Winston Chang
d8274c3d8c Create viewer.R from server.R 2020-09-24 14:37:25 -05:00
Winston Chang
85b5fb090f Add back shinyapp.R 2020-09-24 14:32:20 -05:00
Winston Chang
2adef311ed Merge branch 'wch-rename-fix' into main 2020-09-24 14:31:17 -05:00
Winston Chang
7050d0b8ad Remove shinyapp.R 2020-09-24 14:30:42 -05:00
Winston Chang
8358144a4f Rename file 2020-09-24 14:28:15 -05:00
Winston Chang
44e083e0a9 Re-document 2020-09-24 12:58:06 -05:00
Winston Chang
a5418cf6ee Rename app.R to shinyapp.R 2020-09-24 12:57:27 -05:00
Winston Chang
c74630d6eb Split knitr.R from app.R 2020-09-24 12:55:53 -05:00
Winston Chang
157d4ac9a9 Split knitr.R from app.R 2020-09-24 12:48:32 -05:00
Winston Chang
8228613c01 Create knitr.R from app.R 2020-09-24 12:47:21 -05:00
Winston Chang
b907e17b70 Rebuild shiny.js 2020-09-24 10:49:13 -05:00
Winston Chang
aa7000427c Update NEWS 2020-09-24 10:48:57 -05:00
Winston Chang
8562c90454 Remove allowDataUriScheme because it is no longer needed 2020-09-24 10:47:27 -05:00
Winston Chang
5a9a04cd72 Remove IE8 and IE9 file upload support 2020-09-24 10:47:27 -05:00
Winston Chang
6b32611356 Rebuild shiny.js 2020-09-24 10:41:01 -05:00
colin
770ebc394f updateRadioButton with character(0) (#3043)
Squashed commit of the following:

commit a095d75b67a0bad439e8d6c495ef81af25c0b1a9
Author: Winston Chang <winston@stdout.org>
Date:   Thu Sep 24 10:30:47 2020 -0500

    Update NEWS

commit 715a10ebd63c34eb2f464a7388e0b89b994bee0f
Author: Winston Chang <winston@stdout.org>
Date:   Thu Sep 24 10:24:24 2020 -0500

    Update docs for radioButtons about having none selected

commit eff9036884693002a84f84df16cf699be2358c1c
Author: Winston Chang <winston@stdout.org>
Date:   Thu Sep 24 10:15:59 2020 -0500

    Cleaner check for no selected radioButtons

commit 1666baa746f4dea986be4929720de2a5653acbb6
Merge: c0d35e84 b04ba393
Author: Winston Chang <winston@stdout.org>
Date:   Thu Sep 24 10:02:16 2020 -0500

    Merge branch '2688' of https://github.com/ColinFay/shiny into ColinFay-2688

commit b04ba393b8
Author: colin <colin@thinkr.fr>
Date:   Thu Sep 24 08:37:58 2020 +0200

    changed the test structure

commit 866a86946a
Author: colin <colin@thinkr.fr>
Date:   Sun Sep 13 20:50:44 2020 +0200

    restore old `$escape` behavior

commit d45af353fd
Author: colin <colin@thinkr.fr>
Date:   Fri Sep 11 08:54:25 2020 +0200

    added trailing ; and space before {

commit 5e95ee03a1
Author: colin <colin@thinkr.fr>
Date:   Thu Sep 10 21:55:02 2020 +0200

    return early if the value is undefined in setValue of radio

commit 24ac6ec624
Author: colin <colin@thinkr.fr>
Date:   Thu Sep 10 21:53:41 2020 +0200

    Testing that the type of val is a string, instead of relying on the length

commit 18ec3b8540
Author: colin <colin@thinkr.fr>
Date:   Wed Sep 9 22:08:45 2020 +0200

    Radio buttons can now be reset with character(0), and their value is set to NULL

    Close #2688 and close #2266

commit d7f66165d0
Author: colin <colin@thinkr.fr>
Date:   Wed Sep 9 22:08:06 2020 +0200

    Correct bug when $escape received an empty value
2020-09-24 10:38:12 -05:00
Joe Cheng
c0d35e84b1 Allow setting the state of RestoreContext (#3053)
* Allow setting the state of RestoreContext

This setter only sets public fields, but it's still necessary because
the RestoreInputSet R6 class is not exported.

(I needed this functionality for shinytableau config dialogs to do a
bookmark-like restore, but not at all based on querystring)

* Use list instead of values to prevent accidental mutation

See discussion here:
https://github.com/rstudio/shiny/pull/3053#discussion_r488948453

* Rebuild JS for new version number
2020-09-21 13:27:59 -07:00
Andrew Baxter
5e74478864 Remove test for date object length>1 (Closes #2936) (#3061)
Co-authored-by: Winston Chang <winston@stdout.org>
2020-09-16 17:11:06 -05:00
Winston Chang
46852e2051 Include sources in source maps
Uglify changed the option to include sources; this fix reinstates them.
2020-09-15 15:48:55 -05:00
Winston Chang
b9dded0bef Rebuild JS assets 2020-09-15 15:37:03 -05:00
Winston Chang
6d05f403a5 yarn upgrade 2020-09-15 15:34:47 -05:00
Winston Chang
8368634f85 Merge pull request #2959 from rstudio/joe/feature/select-choices-warning 2020-09-15 15:21:58 -05:00
Winston Chang
8d57d909b4 Merge branch 'master' into joe/feature/select-choices-warning 2020-09-15 15:21:45 -05:00
Winston Chang
9b7855d597 Add more authors 2020-09-15 15:13:42 -05:00
Winston Chang
6a5e1b9998 Add Barret to Authors 2020-09-15 13:15:04 -05:00
Carson Sievert
af6e558699 Make sure we only include one version of Bootstrap (#3048)
* Make sure we only include one version of Bootstrap and throw a warning if both bootstraplib and theme file is provided

* code review
2020-09-11 17:52:08 -05:00
Carson Sievert
26d4dddffd Remove modalButton() from pkgdown reference (it's not included on modalDialog()) (#3046) 2020-09-11 15:04:53 -05:00
Hadley Wickham
e2765b4881 Document modalButton with modalDialog (#2907) 2020-09-11 08:49:21 -05:00
Hadley Wickham
9796b25f33 Combine point events into one doc file (#2906) 2020-09-10 17:47:45 -05:00
Carson Sievert
01b8d3a314 More themable dateInput()/dateRangeInput() (#2964)
* upgrade bootstrap-datepicker from 1.6.4 to 1.9.0; setup infrastructure for bootstraplib theming

Note also that the 000 patch is no longer relevant as 1.9.0 includes the same fix https://github.com/uxsolutions/bootstrap-datepicker/pull/2009

* Patch sass code for BS4 support and more general color contrasting

* Wrap sass compilation into reusable function

* remove check warning

* Have bootstrapPage() use bootstraplib

* yarn build

* Use new output_template()

* Deprecate bootstrapLib() in favor of bootstraplib::bootstrap()

* Require bootstraplib 0.1.0.9001

* Sync up DESCRIPTION

* document

* rollback changes to pkgdown
2020-09-09 15:20:59 -05:00
Carson Sievert
50c48de0de More themable selectInput() (#2950)
* Add option to use bootstraplib and have selectInput() theming variables

* Use getShinyOption()

* Have useBsTheme() error out with informative messages if a theme isn't active

* Better Sass variables defaults that account for both bootswatch themes and bs_theme_base_colors()

* Add Carson as an author

* Provide better BS3/BS4 selectize sass variable defaults as a patch to the source files

* tidy up tools script

* add sass to suggests

* yarn install && yarn build

* Wrap sass compilation into reusable function

* Bring -color-item closer to -color-input

* Leverage the new sass::output_file()

* naming change

* Sync up with other PRs

* Sync up DESCRIPTION

* Forgot to update CSS output file logic

* document
2020-09-09 15:02:05 -05:00
Carson Sievert
bfc90da054 More themable sliderInput() (#2958)
* More themable sliderInput()

* Slider's accent color default should derive from primary theme color

* Remove custom theming args (skin, accentColor, sassVars) but still support theming via bootstraplib

* Wrap sass compilation into reusable function

* remove check warning

* Make font-family configurable; auto-contrast fromto handle text color; increase color contrasting (for accessbility)

* Sync up with other PRs

* Sync up DESCRIPTION

* Forgot to update CSS output file logic

* document

* code review
2020-09-09 14:38:10 -05:00
JooYoung Seo
9d8d6fd6b1 Resolve NEWS conflict 2020-09-09 15:17:25 -04:00
Winston Chang
43344d9a78 Merge pull request #3009 from jooyoungseo/landmark-a11y
Added a11y semantic landmarks for main and sidebar panels
2020-09-09 13:33:04 -05:00
Winston Chang
01a593c857 Rebuild docs 2020-09-09 13:14:39 -05:00
Winston Chang
1b2dd11a4c Merge pull request #2944 from daattali/patch-2 2020-09-09 13:12:36 -05:00
Winston Chang
d90a2c4801 Add links to functions
Co-authored-by: Carson Sievert <cpsievert1@gmail.com>
2020-09-09 13:12:04 -05:00
Winston Chang
f065c21ee6 Merge pull request #2945 from daattali/patch-3
Documentation: say that withProgress returns the value of its express…
2020-09-09 13:11:20 -05:00
Winston Chang
d0324bd497 Merge pull request #3027 from ColinFay/issue-3024 2020-09-09 13:10:31 -05:00
Hadley Wickham
e57fba07db Allow passing server function directory to testServer() (#2965) 2020-09-03 17:01:02 -05:00
Winston Chang
5cb279cf4e Merge pull request #3035 from rstudio/wch-cache-log
Make sure cache logging appends to file
2020-09-02 10:46:45 -05:00
Winston Chang
4f728b0387 Merge pull request #3034 from rstudio/wch-disk-cache-logic 2020-09-02 10:46:33 -05:00
Winston Chang
927ae08a47 Remove unneeded paste0 2020-09-02 10:42:57 -05:00
JooYoung Seo
a28dc47e30 Added es5-shim removal in NEWS.md (#3032) 2020-09-01 21:01:41 -04:00
Winston Chang
b43ee13dd8 Make sure cache logging appends to file 2020-09-01 19:30:42 -05:00
Winston Chang
ad5ad5a675 Update NEWS 2020-09-01 19:20:47 -05:00
Winston Chang
198f7d171e Fix DiskCache pruning logic when max_n and max_size are used. Closes #3033 2020-09-01 19:19:55 -05:00
JooYoung Seo
549425cb81 Merge master branch 2020-08-31 19:12:26 -04:00
JooYoung Seo
6023165268 Merge master branch 2020-08-31 19:02:41 -04:00
Carson Sievert
2a7273c254 Merge pull request #3030 from rstudio/plot-arg-order
Move `alt` parameter after `...`
2020-08-31 17:23:04 -05:00
Winston Chang
8640934410 Move alt parameter after ... 2020-08-31 16:28:43 -05:00
Winston Chang
20bc4e7caa Merge pull request #3006 from jooyoungseo/alttext 2020-08-31 15:49:24 -05:00
Barret Schloerke
9f83058b78 Do not record the reactlog when enabling shinytest (#3025) 2020-08-31 10:39:14 -04:00
colin
ffedf29db4 Other Rds generated by running devtools::document() on the package 2020-08-29 22:27:49 +02:00
colin
00219d342a All update*Input docs now inheritsParams from their standard counterpart
Will close #3024
2020-08-29 22:26:10 +02:00
Winston Chang
753400144d Update diskCache docs and rebuild 2020-08-28 08:58:30 -05:00
Winston Chang
854a732f47 Update NEWS 2020-08-28 08:57:38 -05:00
Winston Chang
03eaf07526 Merge pull request #3016 from aalucaci/issue-2984
Issue 2984
2020-08-28 08:56:16 -05:00
Carson Sievert
d04c12d8cb Merge pull request #3023 from rstudio/carson/bugfix/downloadButton
Change the evaluation rules for the icon promise in downloadButton()
2020-08-27 13:36:44 -05:00
Carson Sievert
afddd3543e Apply suggestions from code review
Co-authored-by: Barret Schloerke <barret@rstudio.com>
2020-08-27 13:35:06 -05:00
Carson
d9459a855d Allow icon arg to reference other downloadButton args 2020-08-27 11:12:09 -05:00
Carson
efbcfca126 Change the evaluation rules for the icon promise in downloadButton(), fixes #3022 2020-08-27 11:07:09 -05:00
Angela Lucaci-Timoce
916675a9bd renderCachedPlot: improved documentation 2020-08-26 21:03:00 +02:00
Colin Fay
7b43617954 downloadButton() icon can now be changed via the icon parameter (#3010) 2020-08-25 15:17:49 -05:00
Winston Chang
09b89bccfd Fix NEWS entry 2020-08-25 13:14:58 -05:00
Winston Chang
1190ee07a9 Remove unused cacheContext class 2020-08-25 13:12:01 -05:00
Barret Schloerke
c4dcf405bb Fix reactiveValuesToList reactlog label (#3017)
Co-authored-by: Barret Schloerke <schloerke@gmail.com>
Co-authored-by: Winston Chang <winston@stdout.org>
2020-08-25 11:49:22 -04:00
JooYoung Seo
c844ea6f07 Added missing alt arg 2020-08-20 10:51:32 -04:00
JooYoung Seo
19704c151a White space formatting to match the lines together
Co-authored-by: Barret Schloerke <barret@rstudio.com>
2020-08-20 10:00:43 -04:00
JooYoung Seo
1281ba18cd Cleaned code 2020-08-19 17:17:40 -04:00
JooYoung Seo
f1f2fae420 Update R/shinyui.R
Used attr instead of attributes()

Co-authored-by: Carson Sievert <cpsievert1@gmail.com>
2020-08-19 15:43:46 -04:00
JooYoung Seo
5809070b05 Used isTRUE inverse instead of isFALSE 2020-08-19 15:23:36 -04:00
JooYoung Seo
2c492540ce Merged master 2020-08-19 15:04:02 -04:00
JooYoung Seo
61556b505d Used attribute instead of option 2020-08-19 15:02:01 -04:00
Winston Chang
d6a4bc87e8 Fix whitespace 2020-08-19 11:48:35 -05:00
JooYoung Seo
e49f4696e6 Updated NEWS.md 2020-08-19 10:50:23 -04:00
JooYoung Seo
4219f50141 Added a11y semantic landmarks for main and sidebar panels 2020-08-19 10:43:55 -04:00
JooYoung Seo
19da003291 Redocumented for alt param 2020-08-18 17:19:45 -04:00
JooYoung Seo
f0765e3d6a Updated alt param description 2020-08-18 17:05:47 -04:00
JooYoung Seo
8dac345512 Updated NEWS.md 2020-08-18 16:44:43 -04:00
JooYoung Seo
ce101843f0 Made alt param reactive 2020-08-18 15:43:04 -04:00
JooYoung Seo
d56dc3a237 Update R/render-cached-plot.R
Co-authored-by: Barret Schloerke <barret@rstudio.com>
2020-08-18 14:25:16 -04:00
JooYoung Seo
28cffb2e25 Update R/render-plot.R
Co-authored-by: Barret Schloerke <barret@rstudio.com>
2020-08-18 14:24:08 -04:00
JooYoung Seo
d2d169fea3 Update R/render-plot.R
Co-authored-by: Barret Schloerke <barret@rstudio.com>
2020-08-18 14:23:17 -04:00
JooYoung Seo
a5eb1b15d2 Added alt param 2020-08-16 16:11:18 -04:00
JooYoung Seo
23dbb0b41c Unified eol in Gruntfile.js for all the platforms (#3001)
* Unified eol char for all the platforms

* Reran yarn build after merging master
2020-08-13 16:54:44 -04:00
Winston Chang
c72ae68de5 Merge pull request #2993 from jooyoungseo/selectize-a11y 2020-08-13 13:56:39 -05:00
JooYoung Seo
7c1f87aed3 Rebuilt via WSL 2020-08-12 19:20:42 -04:00
JooYoung Seo
6ec0ac1651 Reran yarn after updating grunt 2020-08-12 16:34:08 -04:00
JooYoung Seo
9dc84e5c2b Merge branch 'master' into selectize-a11y 2020-08-12 15:24:29 -04:00
JooYoung Seo
1e17b55f49 Got rid of es5 info and corrected selectize version 2020-08-12 15:24:18 -04:00
JooYoung Seo
6a4c8556a3 Merge branch 'master' into lang-a11y 2020-08-12 15:07:46 -04:00
JooYoung Seo
488f1c8b83 Made sure lang length to be 1 2020-08-12 15:07:23 -04:00
JooYoung Seo
e2537d8e93 Used withr for applying datepicker patches 2020-08-12 12:56:13 -04:00
JooYoung Seo
6d35cb6c77 yarn grunt instead of yarn build 2020-08-07 11:20:27 -04:00
Carson Sievert
8ce7f64679 Merge pull request #2995 from jooyoungseo/IonRangeSlider-updateScript
Tweaked updateIonRangeSlider.R
2020-08-07 09:40:42 -05:00
JooYoung Seo
5cd6250f05 Updated NEWS.md 2020-08-06 17:17:08 -04:00
JooYoung Seo
4872cd91a5 Reran yarn build 2020-08-06 17:00:54 -04:00
JooYoung Seo
08e84e2ca0 Tweaked updateSelectize.R 2020-08-06 16:22:47 -04:00
JooYoung Seo
40889c9637 Used withr when applying patches and doing yarn build 2020-08-06 16:12:11 -04:00
JooYoung Seo
010ba6f214 Update tools/updateIonRangeSlider.R
Co-authored-by: Carson Sievert <cpsievert1@gmail.com>
2020-08-06 15:12:26 -04:00
JooYoung Seo
2f8dc860ff Update tools/updateIonRangeSlider.R
Co-authored-by: Carson Sievert <cpsievert1@gmail.com>
2020-08-06 15:11:55 -04:00
JooYoung Seo
88f61f0d45 Update tools/updateIonRangeSlider.R
Co-authored-by: Carson Sievert <cpsievert1@gmail.com>
2020-08-06 15:11:37 -04:00
JooYoung Seo
16a5aa7489 Update tools/updateIonRangeSlider.R
Co-authored-by: Carson Sievert <cpsievert1@gmail.com>
2020-08-06 15:11:19 -04:00
JooYoung Seo
89fd2b2ed3 Tweaked updateIonRangeSlider.R 2020-08-06 13:14:11 -04:00
JooYoung Seo
a16769061e Removed es5 shim 2020-08-05 20:31:33 -04:00
JooYoung Seo
3be76145b7 Updated grunt file to minify selectize-plugin-a11y 2020-08-05 20:23:23 -04:00
JooYoung Seo
e9d27fa632 Update tools/updateSelectize.R
Co-authored-by: Carson Sievert <cpsievert1@gmail.com>
2020-08-05 17:36:16 -04:00
JooYoung Seo
be706e4bb7 Added updating scripts and LICENSE info 2020-08-05 17:15:02 -04:00
JooYoung Seo
b87c4d5623 Appended a11y plugin to options 2020-08-05 11:33:58 -04:00
JooYoung Seo
03a260f26a Defaulting a11y plugins 2020-08-04 22:32:11 -04:00
JooYoung Seo
ae3e007a5f Updated selectize-plugin-a11y 2020-08-04 16:58:23 -04:00
JooYoung Seo
cfbf76d898 Added selectize-plugin-a11y 2020-08-04 14:45:34 -04:00
Carson Sievert
0b82b121cb Merge pull request #2978 from jooyoungseo/dateInput-a11y
* Fixed #2951: Added labels and title for dateInput and dateRangeInput
2020-08-03 09:48:46 -05:00
JooYoung Seo
643ebb4946 Merge branch 'master' of https://github.com/rstudio/shiny into dateInput-a11y 2020-07-31 17:12:40 -04:00
Carson
8693eed3ec use expect_equal() instead of grepl() in expectation 2020-07-31 15:05:05 -05:00
Winston Chang
766b910150 Add info about calling registerInputHandler from .onLoad 2020-07-28 13:58:36 -05:00
Winston Chang
545843ffe6 Fix pkgdown.yml 2020-07-28 12:59:39 -05:00
Winston Chang
39e7b23d5b Merge pull request #2934 from hadley/render-text-print 2020-07-28 11:15:15 -05:00
Hadley Wickham
9d0db6f74c Remove renderPrint from pkgdown index 2020-07-27 15:37:39 -05:00
Winston Chang
78fb25329c NEWS edits 2020-07-27 14:39:37 -05:00
Winston Chang
7db6a7b57a Update NEWS 2020-07-27 14:38:00 -05:00
Winston Chang
76f70179c0 Merge pull request #2982 from ColinFay/patch-2 2020-07-27 14:36:50 -05:00
Winston Chang
d6aecfe9ae Update NEWS 2020-07-27 14:28:13 -05:00
Winston Chang
1354d3dec1 Merge pull request #2981 from ColinFay/patch-1 2020-07-27 14:26:36 -05:00
colin
955ae817d8 switched from * to + in the regex that checks resource path 2020-07-27 21:20:03 +02:00
colin
aee9589c1a Simple regex in addResourcePath 2020-07-25 22:42:09 +02:00
colin
48ac0f55c3 check that the prefix is not only made of dots 2020-07-25 22:38:41 +02:00
colin
831c0a340c redoc the runExample() 2020-07-24 11:46:54 +02:00
Colin Fay
210d297d18 Update server.R 2020-07-24 11:08:28 +02:00
Colin Fay
afbcf9039e Allow to pass resource path that starts with .
This will close #2980
2020-07-24 09:33:52 +02:00
JooYoung Seo
e8eadc1a09 Updated test 2020-07-23 11:11:02 -04:00
JooYoung Seo
f234b7015c Date format instead of format 2020-07-22 16:49:22 -04:00
JooYoung Seo
8de38b3415 Updated NEWS.md 2020-07-22 13:22:45 -04:00
JooYoung Seo
0f132fc180 * Fixed #2951: Added labels and title for dateInput and dateRangeInput 2020-07-22 13:10:45 -04:00
Hadley Wickham
e597c24f35 Merged upstream/master into hadley-render-text-print 2020-07-19 12:59:01 -05:00
Joe Cheng
1d7a913d29 Add tests 2020-07-17 09:56:33 -07:00
Joe Cheng
f89131205d Warn on 1000+ choices for selectInput/selectizeInput 2020-07-17 09:56:05 -07:00
Winston Chang
abc6a98d0f Merge pull request #2974 from jooyoungseo/news-patch 2020-07-16 18:10:59 -05:00
JooYoung Seo
9415e79ff3 Merge branch 'master' of https://github.com/rstudio/shiny into news-patch 2020-07-16 16:47:56 -04:00
JooYoung Seo
6269022536 Followed convention for NEWS.md 2020-07-16 16:47:43 -04:00
Joe Cheng
6ad2125ee7 Calling runApp("app.R") ignored options passed into shinyApp() (#2969)
* Calling `runApp("app.R")` ignored options passed into `shinyApp()`

Fixes #1942.

This was caused by shinyAppDir_appR (which was called by shinyAppDir
and shinyAppFile, which were called when runApp() was used with either
no args or a path) dropping shinyApp() options on the floor.

Fixing this was not as simple as not dropping those options. Before
this commit, the app.R file was not invoked until after the host and
port options (possibly others) were already finalized. This commit
changes the effective sequence of events during startup.

- Calling shinyAppFile() or shinyAppDir() that points to a single-file
  app, now causes the app.R file to be sourced immediately; previously,
  sourcing would happen only at onStart(). (Honestly, the new behavior
  seems less surprising anyway.)

- The support files (R/*.R) for app.R were sourced during onStart. I've
  moved this so that the support files are sourced right before app.R
  is, and re-sourced every time app.R reloads.

* Code review feedback

* Code review feedback: improve test

* Roxygenize
2020-07-16 13:46:32 -07:00
JooYoung Seo
f5d7523a4f Merge pull request #2937 from jooyoungseo/fileInput-a11y
Improved fileInput keyboard accessibility
2020-07-16 16:16:55 -04:00
JooYoung Seo
ce31b9af7e Removed an issue URL from NEWS.md 2020-07-16 16:13:21 -04:00
JooYoung Seo
fc5d980a52 Resolved NEWS.md conflict 2020-07-16 15:43:35 -04:00
JooYoung Seo
9ea726732a Merge branch 'master' of https://github.com/rstudio/shiny 2020-07-16 15:40:10 -04:00
JooYoung Seo
db5f9cca73 Added Bootstrap accessibility plugin (#2911)
Co-authored-by: Winston Chang <winston@stdout.org>
2020-07-16 14:26:11 -05:00
JooYoung Seo
06fb4f6972 Merge branch 'master' of https://github.com/rstudio/shiny 2020-07-16 15:25:28 -04:00
Winston Chang
f045f9cf1b Merge pull request #2970 from rstudio/joe/feature/ui-http-response-2 2020-07-16 14:11:37 -05:00
Winston Chang
1752f57c7d Remove html5shiv and respond.js 2020-07-16 13:56:00 -05:00
Joe Cheng
7eb4bc15b8 Use soft breaks in NEWS 2020-07-16 10:09:43 -07:00
Joe Cheng
707b5ea851 Avoid spurious use of connections 2020-07-16 10:08:51 -07:00
Joe Cheng
fe9f679051 on.exit(add = TRUE)
Co-authored-by: Carson Sievert <cpsievert1@gmail.com>
2020-07-16 10:03:43 -07:00
Joe Cheng
368a49be36 Add PR number to NEWS 2020-07-15 15:53:34 -07:00
Joe Cheng
80f0c5f5d7 Allow function-based UI to respond to non-GET requests 2020-07-15 15:51:36 -07:00
Joe Cheng
a5a7224228 Allow function-based UI to return a complete HTTP response
This allows the UI handler to have total control over the response,
including status code (for redirects) or content type (for serving
up files).
2020-07-15 14:36:54 -07:00
JooYoung Seo
d616cf045b Resolved NEWS.md 2020-07-15 11:17:52 -04:00
JooYoung Seo
8186ae060d Merge branch 'master' of https://github.com/rstudio/shiny 2020-07-15 11:12:04 -04:00
Carson Sievert
c46e80c711 Merge pull request #2941 from rstudio/showtext-fix
Include the pixelratio when setting showtext dpi
2020-07-14 13:53:22 -05:00
Carson
0735ebd7a8 update news 2020-07-14 13:52:18 -05:00
Carson
391bbaa73b Do the same when replaying plot 2020-07-14 13:45:34 -05:00
Carson
fed96c0e45 Include the pixelratio when setting showtext dpi 2020-07-14 13:45:34 -05:00
JooYoung Seo
f97f89a371 Merge branch 'master' of https://github.com/rstudio/shiny 2020-07-10 13:32:21 -04:00
Winston Chang
6352a5322b Rebuild documentation 2020-07-10 11:01:51 -05:00
JooYoung Seo
3473427484 Merge branch 'master' of https://github.com/rstudio/shiny 2020-07-10 11:30:59 -04:00
Winston Chang
d6c1733f0c Merge pull request #2917 from jooyoungseo/icon-a11y 2020-07-10 10:27:50 -05:00
JooYoung Seo
d641ac197b Merged recent shiny release 2020-07-10 11:16:10 -04:00
JooYoung Seo
6a0e41b05e Updated test-bootstrap.R 2020-07-10 11:09:44 -04:00
Winston Chang
e21a9a095e Merge pull request #2961 from rstudio/joe/misc/yarn-upgrade 2020-07-08 12:32:39 -05:00
Joe Cheng
56e1a0b939 Further dep upgrades 2020-07-03 09:23:52 -07:00
Joe Cheng
f9f9127a64 Build JS 2020-07-03 09:21:23 -07:00
Joe Cheng
e0628c4ae3 Upgrade build tools; fix Gruntfile.js for Windows 2020-07-03 09:17:37 -07:00
JooYoung Seo
43be342dea Merge branch 'master' of https://github.com/rstudio/shiny 2020-07-02 12:05:27 -04:00
Winston Chang
9cc7419700 Clarify how testServer expression is evaluated 2020-07-01 15:16:46 -05:00
Winston Chang
f559caf4d0 Bump version to 1.5.0.9000 2020-07-01 15:16:46 -05:00
Dean Attali
9f55cd46d8 Documentation: say that withProgress returns the value of its expression. I didn't know if it does or doesn't and had to test it out, it should be explicit 2020-06-27 13:24:37 -04:00
Dean Attali
5956f6b123 Small documentation addition in withProgress (I did not re-compile roxygen) 2020-06-27 13:18:43 -04:00
JooYoung Seo
41e42b8a53 Improved fileInput keyboard accessibility 2020-06-24 13:28:02 -04:00
JooYoung Seo
f6f5fbd6fb Merge branch 'master' of https://github.com/rstudio/shiny 2020-06-24 13:09:11 -04:00
Hadley Wickham
c7618e3991 Combine documentation of renderPrint() and renderText()
Since they're so closely related, and it makes it easier to see how they differ.
2020-06-23 08:13:55 -05:00
JooYoung Seo
638cddcd5e Merge branch 'master' of https://github.com/rstudio/shiny 2020-06-11 16:33:21 -04:00
JooYoung Seo
a3924f4ab1 Updated aria code and NEWS.md 2020-06-11 16:23:57 -04:00
JooYoung Seo
b1983f0a83 Fixed an incorrect line in tools/README.md for IonRangeSlider 2020-06-11 15:51:31 -04:00
JooYoung Seo
aca9f562e1 Provided auto-label for icon() instead of aria-hidden 2020-06-11 11:51:31 -04:00
JooYoung Seo
8c6a830521 Updated NEWS.md 2020-06-09 15:48:38 -04:00
JooYoung Seo
9142cf19c0 Fixed lang attribute in templates 2020-06-09 14:55:45 -04:00
JooYoung Seo
887b7fb34a Fixed app.r for NULL value of lang argument 2020-06-09 14:29:15 -04:00
JooYoung Seo
1392547783 Redocumentation 2020-06-09 14:20:36 -04:00
JooYoung Seo
735b9b8c7a Updated related scripts, templates, and NEWS.md 2020-06-09 14:19:53 -04:00
JooYoung Seo
cba974ec34 Documentation 2020-06-08 20:10:17 -04:00
JooYoung Seo
421d588a2f Fixed lang attribute in template 2020-06-08 20:09:29 -04:00
JooYoung Seo
8b848277d2 Added lang ShinyOption 2020-06-08 20:08:23 -04:00
JooYoung Seo
8ae19c7243 Added lang attribute to the default template 2020-06-08 16:29:10 -04:00
JooYoung Seo
703f481a9a Improved accessibility for icon() 2020-06-04 16:45:04 -04:00
226 changed files with 9272 additions and 7165 deletions

View File

@@ -1,13 +1,18 @@
Package: shiny
Type: Package
Title: Web Application Framework for R
Version: 1.5.0
Version: 1.5.0.9004
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("Carson", "Sievert", role = "aut", email = "carson@rstudio.com"),
person("Barret", "Schloerke", role = "aut", email = "barret@rstudio.com"),
person("Yihui", "Xie", role = "aut", email = "yihui@rstudio.com"),
person("Jeff", "Allen", role = "aut", email = "jeff@rstudio.com"),
person("Jonathan", "McPherson", role = "aut", email = "jonathan@rstudio.com"),
person("Alan", "Dipert", role = "aut"),
person("Barbara", "Borges", role = "aut"),
person(family = "RStudio", role = "cph"),
person(family = "jQuery Foundation", role = "cph",
comment = "jQuery library and jQuery UI library"),
@@ -23,10 +28,18 @@ Authors@R: c(
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("Prem Nawaz", "Khan", role = "ctb",
comment = "Bootstrap accessibility plugin"),
person("Victor", "Tsaran", role = "ctb",
comment = "Bootstrap accessibility plugin"),
person("Dennis", "Lembree", role = "ctb",
comment = "Bootstrap accessibility plugin"),
person("Srinivasu", "Chakravarthula", role = "ctb",
comment = "Bootstrap accessibility plugin"),
person("Cathy", "O'Connor", role = "ctb",
comment = "Bootstrap accessibility plugin"),
person(family = "PayPal, Inc", role = "cph",
comment = "Bootstrap accessibility plugin"),
person("Stefan", "Petre", role = c("ctb", "cph"),
comment = "Bootstrap-datepicker library"),
person("Andrew", "Rowls", role = c("ctb", "cph"),
@@ -35,10 +48,8 @@ Authors@R: c(
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("Salmen", "Bejaoui", role = c("ctb", "cph"),
comment = "selectize-plugin-a11y library"),
person("Denis", "Ineshin", role = c("ctb", "cph"),
comment = "ion.rangeSlider library"),
person("Sami", "Samhuri", role = c("ctb", "cph"),
@@ -70,7 +81,7 @@ Imports:
jsonlite (>= 0.9.16),
xtable,
digest,
htmltools (>= 0.4.0.9003),
htmltools (>= 0.5.0.9001),
R6 (>= 2.0),
sourcetools,
later (>= 1.0.0),
@@ -81,7 +92,8 @@ Imports:
fastmap (>= 1.0.0),
withr,
commonmark (>= 1.7),
glue (>= 1.3.2)
glue (>= 1.3.2),
bootstraplib (>= 0.2.0.9001)
Suggests:
datasets,
Cairo (>= 1.5-5),
@@ -97,23 +109,27 @@ Suggests:
future,
dygraphs,
ragg,
showtext
showtext,
sass
Remotes:
rstudio/htmltools,
rstudio/sass,
rstudio/bootstraplib
URL: http://shiny.rstudio.com
BugReports: https://github.com/rstudio/shiny/issues
Collate:
'app.R'
'globals.R'
'app-state.R'
'app_template.R'
'bookmark-state-local.R'
'stack.R'
'bookmark-state.R'
'bootstrap-deprecated.R'
'bootstrap-layout.R'
'globals.R'
'conditions.R'
'map.R'
'utils.R'
'bootstrap.R'
'cache-context.R'
'cache-disk.R'
'cache-memory.R'
'cache-utils.R'
@@ -148,6 +164,7 @@ Collate:
'insert-tab.R'
'insert-ui.R'
'jqueryui.R'
'knitr.R'
'middleware-shiny.R'
'middleware.R'
'timer.R'
@@ -164,10 +181,13 @@ Collate:
'render-plot.R'
'render-table.R'
'run-url.R'
'runapp.R'
'serializers.R'
'server-input-handlers.R'
'server-resource-paths.R'
'server.R'
'shiny-options.R'
'shinyapp.R'
'shinyui.R'
'shinywrappers.R'
'showcase.R'
@@ -177,6 +197,7 @@ Collate:
'test-server.R'
'test.R'
'update-input.R'
RoxygenNote: 7.1.0.9000
'viewer.R'
RoxygenNote: 7.1.1
Encoding: UTF-8
Roxygen: list(markdown = TRUE)

447
LICENSE
View File

@@ -8,12 +8,11 @@ these components are included below):
- jQuery, https://github.com/jquery/jquery
- jQuery UI (some components), https://github.com/jquery/jquery-ui
- Bootstrap, https://github.com/twbs/bootstrap
- html5shiv, https://github.com/aFarkas/html5shiv
- Respond.js, https://github.com/scottjehl/Respond
- bootstrap-accessibility-plugin, https://github.com/paypal/bootstrap-accessibility-plugin
- bootstrap-datepicker, https://github.com/eternicode/bootstrap-datepicker
- Font Awesome, https://github.com/FortAwesome/Font-Awesome
- selectize.js, https://github.com/selectize/selectize.js
- es5-shim, https://github.com/es-shims/es5-shim
- selectize-plugin-a11y, https://github.com/SLMNBJ/selectize-plugin-a11y
- ion.rangeSlider, https://github.com/IonDen/ion.rangeSlider
- strftime for Javascript, https://github.com/samsonjs/strftime
- DataTables, https://github.com/DataTables/DataTables
@@ -72,399 +71,35 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
html5shiv License (MIT and GPL-2)
bootstrap-accessibility-plugin (BSD-3-Clause License)
----------------------------------------------------------------------
Copyright (c) 2014 Alexander Farkas (aFarkas).
Licensed under MIT
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.
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) 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
this service 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 make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. 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.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
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
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the 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 a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE 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.
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
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<Html5shiv, The HTML5 Shiv enables use of HTML5 sectioning elements in
legacy Internet Explorer and provides basic HTML5 styling for Internet Explorer 6-9,
Safari 4.x (and iPhone 3.x), and Firefox 3.x.>
Copyright (C) 2014 Alexander Farkas (aFarkas)
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 2 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, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 2014 Alexander Farkas (aFarkas)
Gnomovision 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, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This 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 Library General
Public License instead of this License.
Respond.js License
----------------------------------------------------------------------
Copyright (c) 2012 Scott Jehl
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.
Copyright (c) 2014, PayPal
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 the PayPal nor the names of its
contributors 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 AND CONTRIBUTORS "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 HOLDER OR CONTRIBUTORS 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.
bootstrap-datepicker
@@ -1322,30 +957,18 @@ selectize.js
limitations under the License.
es5-shim License
selectize-plugin-a11y License
----------------------------------------------------------------------
The MIT License (MIT)
Copyright (C) 2009-2014 Kristopher Michael Kowal and contributors
Copyright 2018-present Salmen Bejaoui
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:
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 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.
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.
ion.rangeSlider License

View File

@@ -99,6 +99,7 @@ export(formatStackTrace)
export(freezeReactiveVal)
export(freezeReactiveValue)
export(getCurrentOutputInfo)
export(getCurrentTheme)
export(getDefaultReactiveDomain)
export(getQueryString)
export(getShinyOption)
@@ -116,6 +117,7 @@ export(hoverOpts)
export(hr)
export(htmlOutput)
export(htmlTemplate)
export(httpResponse)
export(icon)
export(imageOutput)
export(img)
@@ -181,6 +183,7 @@ export(printError)
export(printStackTrace)
export(radioButtons)
export(reactive)
export(reactiveConsole)
export(reactiveFileReader)
export(reactivePlot)
export(reactivePoll)
@@ -196,6 +199,7 @@ export(reactlog)
export(reactlogReset)
export(reactlogShow)
export(registerInputHandler)
export(registerThemeDependency)
export(removeInputHandler)
export(removeModal)
export(removeNotification)

78
NEWS.md
View File

@@ -1,3 +1,80 @@
shiny 1.5.0.9000
================
## Full changelog
### Breaking changes
* Closed #3074: Shiny no longer supports file uploads for Internet Explorer 8 or 9. (#3075)
* Subtle changes, and some soft-deprecations, have come to `freezeReactiveValue` and `freezeReactiveVal` (#3055). These functions have been fragile at best in previous releases (issues #1791, #2463, #2946). In this release, we've solved all the problems we know about with `freezeReactiveValue(input, "x")`, by 1) invalidating `input$x` and set it to `NULL` whenever we freeze, and 2) ensuring that, after a freeze, even if the effect of `renderUI` or `updateXXXInput` is to set `input$x` to the same value it already has, this will result in an invalidation (whereas by default, Shiny filters out such spurious assignments).
Similar problems may exist when using `freezeReactiveVal`, and when using `freezeReactiveValue` with non-`input` reactive values objects. But support for those was added mostly for symmetry with `freezeReactiveValue(input)`, and given the above issues, it's not clear to us how you could have used these successfully in the past, or why you would even want to. For this release, we're soft-deprecating both of those uses, but we're more than willing to un-deprecate if it turns out people are using these; if that includes you, please join the conversation at https://github.com/rstudio/shiny/issues/3063. In the meantime, you can squelch the deprecation messages for these functions specifically, by setting `options(shiny.deprecation.messages.freeze = FALSE)`.
### Accessibility
* Added [bootstrap accessibility plugin](https://github.com/paypal/bootstrap-accessibility-plugin) under the hood to improve accessibility of shiny apps for screen-reader and keyboard users: the enhancements include better navigations for alert, tooltip, popover, modal dialog, dropdown, tab Panel, collapse, and carousel elements. (#2911)
* Added appropriate labels to `icon()` element to provide screen-reader users with alternative descriptions for the `fontawesome` and `glyphicon`: `aria-label` is automatically applied based on the fontawesome name. For example, `icon("calendar")` will be announced as "calendar icon" to screen readers. "presentation" aria role has also been attached to `icon()` to remove redundant semantic info for screen readers. (#2917)
* Closed #2929: Fixed keyboard accessibility for file picker button: keyboard users can now tab to focus on `fileInput()` widget. (#2937)
* Fixed #2951: screen readers correctly announce labels and date formats for `dateInput()` and `dateRangeInput()` widgets. (#2978)
* Closed #2847: `selectInput()` is reasonably accessible for screen readers even when `selectize` option is set to TRUE. To improve `selectize.js` accessibility, we have added [selectize-plugin-a11y](https://github.com/SLMNBJ/selectize-plugin-a11y) by default. (#2993)
* Closed #612: Added `alt` argument to `renderPlot()` and `renderCachedPlot()` to specify descriptive texts for `plotOutput()` objects, which is essential for screen readers. By default, alt text is set to the static text, "Plot object," but even dynamic text can be made with reactive function. (#3006, thanks @trafficonese and @leonawicz for the original PR and discussion via #2494)
* Added semantic landmarks for `mainPanel()` and `sidebarPanel()` so that assistive technologies can recognize them as "main" and "complementary" region respectively. (#3009)
* Closed #2844: Added `lang` argument to ui `*Page()` functions (e.g., `fluidPage`, `bootstrapPage`) that specifies document-level language within the app for the accessibility of screen readers and search-engine parsers. By default, it is set to empty string which is commonly recognized as a browser's default locale. (#2920)
### Minor new features and improvements
* New `reactiveConsole()` makes it easier to interactively experiment with reactivity at the console (#2518).
* When UI is specified as a function (e.g. `ui <- function(req) { ... }`), the response can now be an HTTP response as returned from the (newly exported) `httpResponse()` function. (#2970)
* `selectInput` and `selectizeInput` now warn about performance implications when thousands of choices are used, and recommend [server-side selectize](https://shiny.rstudio.com/articles/selectize.html) be used instead. (#2959)
* Closed #2980: `addResourcePath()` now allows paths with a leading `.` (thanks to @ColinFay). (#2981)
* Closed #2972: `runExample()` now supports the `shiny.port` option (thanks to @ColinFay). (#2982)
* Closed #2692: `downloadButton()` icon can now be changed via the `icon` parameter (thanks to @ColinFay). (#3010)
* Closed #2984: improved documentation for `renderCachedPlot()` (thanks to @aalucaci). (#3016)
* `reactiveValuesToList()` will save its `reactlog` label as `reactiveValuesToList(<ID>)` vs `as.list(<ID>)` (#3017)
* Removed unused (and non-exported) `cacheContext` class.
* `testServer()` can accept a single server function as input (#2965).
* `shinyOptions()` now has session-level scoping, in addition to global and application-level scoping. (#3080)
### Bug fixes
* Fixed #2859: `renderPlot()` wasn't correctly setting `showtext::showtext_opts()`'s `dpi` setting with the correct resolution on high resolution displays; which means, if the font was rendered by showtext, font sizes would look smaller than they should on such displays. (#2941)
* Fixed #1942: Calling `runApp("app.R")` no longer ignores options passed into `shinyApp()`. This makes it possible for Shiny apps to specify what port/host should be used by default. (#2969)
* Fixed #3033: When a `DiskCache` was created with both `max_n` and `max_size`, too many items could get pruned when `prune()` was called. (#3034)
* Fixed #2936: `dateYMD` was giving a warning when passed a vector of dates from `dateInput` which was greater than length 1. The length check was removed because it was not needed. (#3061)
* Fixed #2266, #2688: `radioButtons` and `updateRadioButtons` now accept `character(0)` to indicate that none of the options should be selected (thanks to @ColinFay). (#3043)
* Fixed a bug that `textAreaInput()` doesn't work as expected for relative `width` (thanks to @shrektan). (#2049)
### Library updates
* Removed html5shiv and respond.js, which were used for IE 8 and IE 9 compatibility. (#2973)
* Removed es5-shim library, which was internally used within `selectInput()` for ECMAScript 5 compatibility. (#2993)
shiny 1.5.0
===========
@@ -309,6 +386,7 @@ This is a significant release for Shiny, with a major new feature that was nearl
* Fixed #2021: Memory leak with `reactiveTimer` and `invalidateLater`. (#2022)
### Library updates
* Updated to ion.rangeSlider 2.2.0. (#1955)

26
R/app-state.R Normal file
View File

@@ -0,0 +1,26 @@
#' @include globals.R
NULL
# The current app state is a place to read and hang state for the
# currently-running application. This is useful for setting options that will
# last as long as the application is running.
.globals$appState <- NULL
initCurrentAppState <- function(appobj) {
if (!is.null(.globals$appState)) {
stop("Can't initialize current app state when another is currently active.")
}
.globals$appState <- new.env(parent = emptyenv())
.globals$appState$app <- appobj
# Copy over global options
.globals$appState$options <- .globals$options
}
getCurrentAppState <- function() {
.globals$appState
}
clearCurrentAppState <- function() {
.globals$appState <- NULL
}

View File

@@ -217,6 +217,22 @@ RestoreContext <- R6Class("RestoreContext",
self$dir <- NULL
},
# Completely replace the state
set = function(active = FALSE, initErrorMessage = NULL, input = list(), values = list(), dir = NULL) {
# Validate all inputs
stopifnot(is.logical(active))
stopifnot(is.null(initErrorMessage) || is.character(initErrorMessage))
stopifnot(is.list(input))
stopifnot(is.list(values))
stopifnot(is.null(dir) || is.character(dir))
self$active <- active
self$initErrorMessage <- initErrorMessage
self$input <- RestoreInputSet$new(input)
self$values <- list2env2(values, parent = emptyenv())
self$dir <- dir
},
# This should be called before a restore context is popped off the stack.
flushPending = function() {
self$input$flushPending()
@@ -453,7 +469,7 @@ hasCurrentRestoreContext <- function() {
domain <- getDefaultReactiveDomain()
if (!is.null(domain) && !is.null(domain$restoreContext))
return(TRUE)
return(FALSE)
}

View File

@@ -16,6 +16,7 @@
#' @param theme Alternative Bootstrap stylesheet (normally a css file within the
#' www directory). For example, to use the theme located at
#' `www/bootstrap.css` you would use `theme = "bootstrap.css"`.
#' @inheritParams bootstrapPage
#'
#' @return A UI defintion that can be passed to the [shinyUI] function.
#'
@@ -87,11 +88,12 @@
#' }
#' @rdname fluidPage
#' @export
fluidPage <- function(..., title = NULL, responsive = NULL, theme = NULL) {
fluidPage <- function(..., title = NULL, responsive = NULL, theme = NULL, lang = NULL) {
bootstrapPage(div(class = "container-fluid", ...),
title = title,
responsive = responsive,
theme = theme)
theme = theme,
lang = lang)
}
@@ -118,6 +120,7 @@ fluidRow <- function(...) {
#' @param theme Alternative Bootstrap stylesheet (normally a css file within the
#' www directory). For example, to use the theme located at
#' `www/bootstrap.css` you would use `theme = "bootstrap.css"`.
#' @inheritParams bootstrapPage
#'
#' @return A UI defintion that can be passed to the [shinyUI] function.
#'
@@ -156,11 +159,12 @@ fluidRow <- function(...) {
#'
#' @rdname fixedPage
#' @export
fixedPage <- function(..., title = NULL, responsive = NULL, theme = NULL) {
fixedPage <- function(..., title = NULL, responsive = NULL, theme = NULL, lang = NULL) {
bootstrapPage(div(class = "container", ...),
title = title,
responsive = responsive,
theme = theme)
theme = theme,
lang = lang)
}
#' @rdname fixedPage
@@ -355,6 +359,8 @@ sidebarLayout <- function(sidebarPanel,
sidebarPanel <- function(..., width = 4) {
div(class=paste0("col-sm-", width),
tags$form(class="well",
# A11y semantic landmark for sidebar
role="complementary",
...
)
)
@@ -364,6 +370,8 @@ sidebarPanel <- function(..., width = 4) {
#' @rdname sidebarLayout
mainPanel <- function(..., width = 8) {
div(class=paste0("col-sm-", width),
# A11y semantic landmark for main region
role="main",
...
)
}

View File

@@ -16,8 +16,15 @@ NULL
#' @param title The browser window title (defaults to the host URL of the page)
#' @param responsive This option is deprecated; it is no longer optional with
#' Bootstrap 3.
#' @param theme Alternative Bootstrap stylesheet (normally a css file within the
#' www directory, e.g. `www/bootstrap.css`)
#' @param theme One of the following:
#' * `NULL` (the default), which implies a "stock" build of Bootstrap 3.
#' * A [bootstraplib::bs_theme()] object. This can be used to replace a stock
#' build of Bootstrap 3 with a customized version of Bootstrap 3 or higher.
#' * A character string pointing to an alternative Bootstrap stylesheet
#' (normally a css file within the www directory, e.g. `www/bootstrap.css`).
#' @param lang ISO 639-1 language code for the HTML page, such as "en" or "ko".
#' This will be used as the lang in the \code{<html>} tag, as in \code{<html lang="en">}.
#' The default (NULL) results in an empty string.
#'
#' @return A UI defintion that can be passed to the [shinyUI] function.
#'
@@ -26,56 +33,196 @@ NULL
#'
#' @seealso [fluidPage()], [fixedPage()]
#' @export
bootstrapPage <- function(..., title = NULL, responsive = NULL, theme = NULL) {
bootstrapPage <- function(..., title = NULL, responsive = NULL, theme = NULL, lang = NULL) {
if (!is.null(responsive)) {
shinyDeprecated("The 'responsive' argument is no longer used with Bootstrap 3.")
}
attachDependencies(
tagList(
if (!is.null(title)) tags$head(tags$title(title)),
if (!is.null(theme)) {
tags$head(tags$link(rel="stylesheet", type="text/css", href = theme))
},
# remainder of tags passed to the function
list(...)
),
bootstrapLib()
ui <- tagList(
bootstrapLib(theme),
if (!is.null(title)) tags$head(tags$title(title)),
# TODO: throw better error when length > 1?
if (is.character(theme)) {
tags$head(tags$link(rel="stylesheet", type="text/css", href = theme))
},
# remainder of tags passed to the function
list(...)
)
ui <- setLang(ui, lang)
return(ui)
}
setLang <- function(ui, lang) {
# Add lang attribute to be passed to renderPage function
attr(ui, "lang") <- lang
ui
}
getLang <- function(ui) {
# Check if ui has lang attribute; otherwise, NULL
attr(ui, "lang", exact = TRUE)
}
#' Bootstrap libraries
#'
#' This function returns a set of web dependencies necessary for using Bootstrap
#' This function defines a set of web dependencies necessary for using Bootstrap
#' components in a web page.
#'
#' It isn't necessary to call this function if you use
#' [bootstrapPage()] or others which use `bootstrapPage`, such
#' [basicPage()], [fluidPage()], [fillPage()],
#' [pageWithSidebar()], and [navbarPage()], because they
#' already include the Bootstrap web dependencies.
#' It isn't necessary to call this function if you use [bootstrapPage()] or
#' others which use `bootstrapPage`, such [fluidPage()], [navbarPage()],
#' [fillPage()], etc, because they already include the Bootstrap web dependencies.
#'
#' @inheritParams bootstrapPage
#' @export
bootstrapLib <- function(theme = NULL) {
htmlDependency("bootstrap", "3.4.1",
tagFunction(function() {
# If we're not compiling Bootstrap Sass (from bootstraplib), return the
# static Bootstrap build.
if (!is_bs_theme(theme)) {
# We'll enter here if `theme` is the path to a .css file, like that
# provided by `shinythemes::shinytheme("darkly")`.
return(bootstrapDependency(theme))
}
# Make bootstrap Sass available so other tagFunction()s (e.g.,
# sliderInput() et al) can resolve their HTML dependencies at render time
# using getCurrentTheme(). Note that we're making an implicit assumption
# that this tagFunction() executes *before* all other tagFunction()s; but
# that should be fine considering that, DOM tree order is preorder,
# depth-first traversal, and at least in the bootstrapPage(theme) case, we
# have control over the relative ordering.
# https://dom.spec.whatwg.org/#concept-tree
# https://stackoverflow.com/a/16113998/1583084
#
# Note also that since this is shinyOptions() (and not options()), the
# option is automatically reset when the app (or session) exits
if (isRunning()) {
setCurrentTheme(theme)
print("is running! and registering bs_theme_dependencies_css")
registerThemeDependency(bs_theme_dependencies_css)
} else {
# Technically, this a potential issue (someone trying to execute/render
# bootstrapLib outside of a Shiny app), but it seems that, in that case,
# you likely have other problems, since sliderInput() et al. already assume
# that Shiny is the one doing the rendering
#warning(
# "It appears `shiny::bootstrapLib()` was rendered outside of an Shiny ",
# "application context, likely by calling `as.tags()`, `as.character()`, ",
# "or `print()` directly on `bootstrapLib()` or UI components that may ",
# "depend on it (e.g., `fluidPage()`, etc). For 'themable' UI components ",
# "(e.g., `sliderInput()`, `selectInput()`, `dateInput()`, etc) to style ",
# "themselves based on the Bootstrap theme, make sure `bootstrapLib()` is ",
# "provided directly to the UI and that the UI is provided direction to ",
# "`shinyApp()` (or `runApp()`)", call. = FALSE
#)
}
bootstraplib::bs_theme_dependencies(theme)
})
}
# This is defined outside of bootstrapLib() because registerThemeDependency()
# wants non-anonymous functions.
bs_theme_dependencies_css <- function(theme) {
deps <- bootstraplib::bs_theme_dependencies(theme)
# Extract out the CSS files only (no need to re-send JS files, even though
# they wouldn't be re-rendered on the client anyway.)
Filter(deps, f = function(dep) !is.null(dep$stylesheet))
}
is_bs_theme <- function(x) {
is_available("bootstraplib", "0.2.0.9000") &&
bootstraplib::is_bs_theme(x)
}
#' Obtain Shiny's Bootstrap Sass theme
#'
#' Intended for use by Shiny developers to create Shiny bindings with intelligent
#' styling based on the [bootstrapLib()]'s `theme` value.
#'
#' @return If called at render-time (i.e., inside a [htmltools::tagFunction()]),
#' and [bootstrapLib()]'s `theme` has been set to a [bootstraplib::bs_theme()]
#' object, then this returns the `theme`. Otherwise, this returns `NULL`.
#' @seealso [getCurrentOutputInfo()], [bootstrapLib()], [htmltools::tagFunction()]
#'
#' @keywords internal
#' @export
getCurrentTheme <- function() {
getShinyOption("bootstrapTheme")
}
setCurrentTheme <- function(theme) {
shinyOptions(bootstrapTheme = theme)
}
#' Register a theme dependency
#'
#' This function registers a function that returns an [htmlDependency()] or list
#' of such objects. If `session$setCurrentTheme()` is called, the function will
#' be re-executed, and the resulting html dependency will be sent to the client.
#'
#' Note that `func` should **not** be an anonymous function, or a function which
#' is defined within the calling function. This is so that,
#' `registerThemeDependency()` is called multiple times with the function, it
#' tries to deduplicate them
#'
#' @param func A function that takes one argument, `theme` (which is a
#' [sass::sass_layer()] object), and returns an htmlDependency object, or list
#' of them.
#'
#' @export
#' @keywords internal
registerThemeDependency <- function(func) {
func_expr <- substitute(func)
if (is.call(func_expr) && identical(func_expr[[1]], as.symbol("function"))) {
warning("`func` should not be an anonymous function. ",
"It should be declared outside of the function that calls registerThemeDependency(); ",
"otherwise it will not be deduplicated by Shiny and multiple copies of the ",
"resulting htmlDependency may be computed and sent to the client.")
}
if (!is.function(func) || length(formals(func)) != 1) {
stop("`func` must be a function with one argument (the current theme)")
}
# Note that this will automatically scope to the app or session level,
# depending on if this is called from within a session or not.
funcs <- getShinyOption("themeDependencyFuncs", list())
str(funcs)
# Don't add func if it's already present.
have_func <- any(vapply(funcs, identical, logical(1), func))
if (!have_func) {
funcs[[length(funcs) + 1]] <- func
}
str(funcs)
shinyOptions("themeDependencyFuncs" = funcs)
}
bootstrapDependency <- function(theme) {
htmlDependency(
"bootstrap", "3.4.1",
c(
href = "shared/bootstrap",
file = system.file("www/shared/bootstrap", package = "shiny")
),
script = c(
"js/bootstrap.min.js",
# These shims are necessary for IE 8 compatibility
"shim/html5shiv.min.js",
"shim/respond.min.js"
# Safely adding accessibility plugin for screen readers and keyboard users; no break for sighted aspects (see https://github.com/paypal/bootstrap-accessibility-plugin)
"accessibility/js/bootstrap-accessibility.min.js"
),
stylesheet = c(
theme %OR% "css/bootstrap.min.css",
# Safely adding accessibility plugin for screen readers and keyboard users; no break for sighted aspects (see https://github.com/paypal/bootstrap-accessibility-plugin)
"accessibility/css/bootstrap-accessibility.css"
),
stylesheet = if (is.null(theme)) "css/bootstrap.min.css",
meta = list(viewport = "width=device-width, initial-scale=1")
)
}
#' @rdname bootstrapPage
#' @export
basicPage <- function(...) {
@@ -129,6 +276,7 @@ basicPage <- function(...) {
#' shown in the document).
#' @param bootstrap If `TRUE`, load the Bootstrap CSS library.
#' @param theme URL to alternative Bootstrap stylesheet.
#' @inheritParams bootstrapPage
#'
#' @family layout functions
#'
@@ -156,7 +304,7 @@ basicPage <- function(...) {
#' )
#' @export
fillPage <- function(..., padding = 0, title = NULL, bootstrap = TRUE,
theme = NULL) {
theme = NULL, lang = NULL) {
fillCSS <- tags$head(tags$style(type = "text/css",
"html, body { width: 100%; height: 100%; overflow: hidden; }",
@@ -164,14 +312,18 @@ fillPage <- function(..., padding = 0, title = NULL, bootstrap = TRUE,
))
if (isTRUE(bootstrap)) {
bootstrapPage(title = title, theme = theme, fillCSS, ...)
ui <- bootstrapPage(title = title, theme = theme, fillCSS, lang = lang, ...)
} else {
tagList(
ui <- tagList(
fillCSS,
if (!is.null(title)) tags$head(tags$title(title)),
...
)
ui <- setLang(ui, lang)
}
return(ui)
}
collapseSizes <- function(padding) {
@@ -223,6 +375,7 @@ collapseSizes <- function(padding) {
#' `www/bootstrap.css` you would use `theme = "bootstrap.css"`.
#' @param windowTitle The title that should be displayed by the browser window.
#' Useful if `title` is not a string.
#' @inheritParams bootstrapPage
#' @param icon Optional icon to appear on a `navbarMenu` tab.
#'
#' @return A UI defintion that can be passed to the [shinyUI] function.
@@ -267,7 +420,8 @@ navbarPage <- function(title,
fluid = TRUE,
responsive = NULL,
theme = NULL,
windowTitle = title) {
windowTitle = title,
lang = NULL) {
if (!missing(collapsable)) {
shinyDeprecated("`collapsable` is deprecated; use `collapsible` instead.")
@@ -338,6 +492,7 @@ navbarPage <- function(title,
title = windowTitle,
responsive = responsive,
theme = theme,
lang = lang,
tags$nav(class=navbarClass, role="navigation", containerDiv),
contentDiv
)
@@ -1309,6 +1464,7 @@ uiOutput <- htmlOutput
#' is assigned to.
#' @param label The label that should appear on the button.
#' @param class Additional CSS classes to apply to the tag, if any.
#' @param icon An [icon()] to appear on the button. Default is `icon("download")`.
#' @param ... Other arguments to pass to the container tag function.
#'
#' @examples
@@ -1339,13 +1495,15 @@ uiOutput <- htmlOutput
#' @export
downloadButton <- function(outputId,
label="Download",
class=NULL, ...) {
class=NULL,
...,
icon = shiny::icon("download")) {
aTag <- tags$a(id=outputId,
class=paste('btn btn-default shiny-download-link', class),
href='',
target='_blank',
download=NA,
icon("download"),
validateIcon(icon),
label, ...)
}
@@ -1422,7 +1580,7 @@ icon <- function(name, class = NULL, lib = "font-awesome") {
if (!is.null(class))
iconClass <- paste(iconClass, class)
iconTag <- tags$i(class = iconClass)
iconTag <- tags$i(class = iconClass, role = "presentation", `aria-label` = paste(name, "icon"))
# font-awesome needs an additional dependency (glyphicon is in bootstrap)
if (lib == "font-awesome") {

View File

@@ -1,77 +0,0 @@
# 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 <- R6Class(
'CacheContext',
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 (inherits(newMtime, 'try-error'))
return(TRUE)
return(!identical(mtime, newMtime))
})
invisible()
},
forceDirty = function() {
.dirty <<- TRUE
.tests <<- list()
invisible()
},
isDirty = function() {
if (.dirty)
return(TRUE)
for (test in .tests) {
if (test()) {
forceDirty()
return(TRUE)
}
}
return(FALSE)
},
reset = function() {
.dirty <<- FALSE
.tests <<- list()
},
with = function(func) {
oldCC <- .currentCacheContext$cc
.currentCacheContext$cc <- self
on.exit(.currentCacheContext$cc <- oldCC)
return(func())
}
)
)
.currentCacheContext <- new.env()
# 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)
}

View File

@@ -130,8 +130,8 @@
#' if an object is in the cache, and then call `get(key)`, the object may
#' be removed from the cache in between those two calls, and `get(key)`
#' will throw an error. Instead of calling the two functions, it is better to
#' simply call `get(key)`, and use `tryCatch()` to handle the error
#' that is thrown if the object is not in the cache. This effectively tests for
#' simply call `get(key)`, and check that the returned object is not a
#' `key_missing()` object, using `is.key_missing()`. This effectively tests for
#' existence and gets the object in one operation.
#'
#' It is also possible for one processes to prune objects at the same time that
@@ -387,7 +387,7 @@ DiskCache <- R6Class("DiskCache",
# is because it is expensive to find the size of the serialized object
# before adding it.
private$log(paste0('prune'))
private$log('prune')
self$is_destroyed(throw = TRUE)
current_time <- Sys.time()
@@ -407,7 +407,11 @@ DiskCache <- R6Class("DiskCache",
rm_idx <- timediff > private$max_age
if (any(rm_idx)) {
private$log(paste0("prune max_age: Removing ", paste(info$name[rm_idx], collapse = ", ")))
file.remove(info$name[rm_idx])
rm_success <- file.remove(info$name[rm_idx])
# This maps rm_success back into the TRUEs in the rm_idx vector.
# If (for example) rm_idx is c(F,T,F,T,T) and rm_success is c(T,F,T),
# then this line modifies rm_idx to be c(F,T,F,F,T).
rm_idx[rm_idx] <- rm_success
info <- info[!rm_idx, ]
}
}
@@ -428,7 +432,8 @@ DiskCache <- R6Class("DiskCache",
rm_idx <- seq_len(nrow(info)) > private$max_n
private$log(paste0("prune max_n: Removing ", paste(info$name[rm_idx], collapse = ", ")))
rm_success <- file.remove(info$name[rm_idx])
info <- info[!rm_success, ]
rm_idx[rm_idx] <- rm_success
info <- info[!rm_idx, ]
}
# 3. Remove files if cache is too large.
@@ -438,7 +443,8 @@ DiskCache <- R6Class("DiskCache",
rm_idx <- cum_size > private$max_size
private$log(paste0("prune max_size: Removing ", paste(info$name[rm_idx], collapse = ", ")))
rm_success <- file.remove(info$name[rm_idx])
info <- info[!rm_success, ]
rm_idx[rm_idx] <- rm_success
info <- info[!rm_idx, ]
}
private$prune_last_time <- as.numeric(current_time)
@@ -555,7 +561,7 @@ DiskCache <- R6Class("DiskCache",
if (is.null(private$logfile)) return()
text <- paste0(format(Sys.time(), "[%Y-%m-%d %H:%M:%OS3] DiskCache "), text)
writeLines(text, private$logfile)
cat(text, sep = "\n", file = private$logfile, append = TRUE)
}
)
)

View File

@@ -359,7 +359,7 @@ MemoryCache <- R6Class("MemoryCache",
if (is.null(private$logfile)) return()
text <- paste0(format(Sys.time(), "[%Y-%m-%d %H:%M:%OS3] MemoryCache "), text)
writeLines(text, private$logfile)
cat(text, sep = "\n", file = private$logfile, append = TRUE)
}
)
)

View File

@@ -87,7 +87,8 @@ reactlog <- function() {
}
#' @describeIn reactlog Display a full reactlog graph for all sessions.
#' @inheritParams reactlog::reactlog_show
#' @param time A boolean that specifies whether or not to display the
#' time that each reactive takes to calculate a result.
#' @export
reactlogShow <- function(time = TRUE) {
check_reactlog()
@@ -179,10 +180,10 @@ RLog <- R6Class(
paste0("names(", reactId, ")")
},
asListIdStr = function(reactId) {
paste0("as.list(", reactId, ")")
paste0("reactiveValuesToList(", reactId, ")")
},
asListAllIdStr = function(reactId) {
paste0("as.list(", reactId, ", all.names = TRUE)")
paste0("reactiveValuesToList(", reactId, ", all.names = TRUE)")
},
keyIdStr = function(reactId, key) {
paste0(reactId, "$", key)

View File

@@ -1,15 +1,26 @@
#' Create an object representing click options
#' Control interactive plot point events
#'
#' This generates an object representing click options, to be passed as the
#' `click` argument of [imageOutput()] or
#' [plotOutput()].
#' These functions give control over the `click`, `dblClick` and
#' `hover` events generated by [imageOutput()] and [plotOutput()].
#'
#' @param id Input value name. For example, if the value is `"plot_click"`,
#' then the click coordinates will be available as `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.
#' then the event data will be available as `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.
#' @param delay For `dblClickOpts()`: the maximum delay (in ms) between a
#' pair clicks for them to be counted as a double-click.
#'
#' For `hoverOpts()`: how long to delay (in ms) 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 `"throttle"` to limit the number of hover events to one
#' every `delay` milliseconds. Use `"debounce"` to suspend events
#' while the cursor is moving, and wait until the cursor has been at rest for
#' `delay` milliseconds before sending an event.
#' @seealso [brushOpts()] for brushing events.
#' @export
#' @keywords internal
clickOpts <- function(id, clip = TRUE) {
if (is.null(id))
stop("id must not be NULL")
@@ -21,21 +32,8 @@ clickOpts <- function(id, clip = TRUE) {
}
#' Create an object representing double-click options
#'
#' This generates an object representing dobule-click options, to be passed as
#' the `dblclick` argument of [imageOutput()] or
#' [plotOutput()].
#'
#' @param id Input value name. For example, if the value is
#' `"plot_dblclick"`, then the click coordinates will be available as
#' `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
#' @rdname clickOpts
dblclickOpts <- function(id, clip = TRUE, delay = 400) {
if (is.null(id))
stop("id must not be NULL")
@@ -47,28 +45,11 @@ dblclickOpts <- function(id, clip = TRUE, delay = 400) {
)
}
#' Create an object representing hover options
#'
#' This generates an object representing hovering options, to be passed as the
#' `hover` argument of [imageOutput()] or
#' [plotOutput()].
#'
#' @param id Input value name. For example, if the value is `"plot_hover"`,
#' then the hover coordinates will be available as `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 `"throttle"` to limit the number of hover events to one
#' every `delay` milliseconds. Use `"debounce"` to suspend events
#' while the cursor is moving, and wait until the cursor has been at rest for
#' `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 `TRUE` (the default), the value will be set to
#' `NULL` when the mouse exits the plotting area. If `FALSE`, the
#' value will stop changing when the cursor exits the plotting area.
#' @export
#' @rdname clickOpts
hoverOpts <- function(id, delay = 300,
delayType = c("debounce", "throttle"), clip = TRUE,
nullOutside = TRUE) {
@@ -116,6 +97,7 @@ hoverOpts <- function(id, delay = 300,
#' `FALSE`, is useful if you want to update the plot while keeping the
#' brush. Using `TRUE` is useful if you want to clear the brush whenever
#' the plot is updated.
#' @seealso [clickOpts()] for clicking events.
#' @export
brushOpts <- function(id, fill = "#9cf", stroke = "#036",
opacity = 0.25, delay = 300,

View File

@@ -110,6 +110,10 @@ dateInput <- function(inputId, label, value = NULL, min = NULL, max = NULL,
shinyInputLabel(inputId, label),
tags$input(type = "text",
class = "form-control",
# `aria-labelledby` attribute is required for accessibility to avoid doubled labels (#2951).
`aria-labelledby` = paste0(inputId, "-label"),
# title attribute is announced for screen readers for date format.
title = paste("Date format:", format),
`data-date-language` = language,
`data-date-week-start` = weekstart,
`data-date-format` = format,
@@ -124,19 +128,48 @@ dateInput <- function(inputId, label, value = NULL, min = NULL, max = NULL,
`data-date-days-of-week-disabled` =
jsonlite::toJSON(daysofweekdisabled, null = 'null')
),
datePickerDependency
datePickerDependency()
)
}
datePickerDependency <- htmlDependency(
"bootstrap-datepicker", "1.6.4", c(href = "shared/datepicker"),
script = "js/bootstrap-datepicker.min.js",
stylesheet = "css/bootstrap-datepicker3.min.css",
# Need to enable noConflict mode. See #1346.
head = "<script>
(function() {
var datepicker = $.fn.datepicker.noConflict();
$.fn.bsDatepicker = datepicker;
})();
</script>"
)
datePickerVersion <- "1.9.0"
datePickerDependency <- function(theme) {
list(
htmlDependency(
name = "bootstrap-datepicker-js",
version = datePickerVersion,
src = c(href = "shared/datepicker"),
script = "js/bootstrap-datepicker.min.js",
# Need to enable noConflict mode. See #1346.
head = "<script>(function() {
var datepicker = $.fn.datepicker.noConflict();
$.fn.bsDatepicker = datepicker;
})();
</script>"
),
bootstraplib::bs_dependency_defer(datePickerCSS)
)
}
datePickerCSS <- function(theme) {
if (!is_bs_theme(theme)) {
return(htmlDependency(
name = "bootstrap-datepicker-css",
version = datePickerVersion,
src = c(href = "shared/datepicker"),
stylesheet = "css/bootstrap-datepicker3.min.css"
))
}
scss_file <- system.file(package = "shiny", "www/shared/datepicker/scss/build3.scss")
bootstraplib::bs_dependency(
input = sass::sass_file(scss_file),
theme = theme,
name = "bootstrap-datepicker",
version = datePickerVersion,
cache_key_extra = utils::packageVersion("shiny")
)
}

View File

@@ -100,6 +100,10 @@ dateRangeInput <- function(inputId, label, start = NULL, end = NULL,
tags$input(
class = "form-control",
type = "text",
# `aria-labelledby` attribute is required for accessibility to avoid doubled labels (#2951).
`aria-labelledby` = paste0(inputId, "-label"),
# title attribute is announced for screen readers for date format.
title = paste("Date format:", format),
`data-date-language` = language,
`data-date-week-start` = weekstart,
`data-date-format` = format,
@@ -118,6 +122,10 @@ dateRangeInput <- function(inputId, label, start = NULL, end = NULL,
tags$input(
class = "form-control",
type = "text",
# `aria-labelledby` attribute is required for accessibility to avoid doubled labels (#2951).
`aria-labelledby` = paste0(inputId, "-label"),
# title attribute is announced for screen readers for date format.
title = paste("Date format:", format),
`data-date-language` = language,
`data-date-week-start` = weekstart,
`data-date-format` = format,
@@ -129,6 +137,6 @@ dateRangeInput <- function(inputId, label, start = NULL, end = NULL,
)
)
),
datePickerDependency
datePickerDependency()
)
}

View File

@@ -91,7 +91,8 @@ fileInput <- function(inputId, label, multiple = FALSE, accept = NULL,
id = inputId,
name = inputId,
type = "file",
style = "display: none;",
# Don't use "display: none;" style, which causes keyboard accessibility issue; instead use the following workaround: https://css-tricks.com/places-its-tempting-to-use-display-none-but-dont/
style = "position: absolute !important; top: -99999px !important; left: -99999px !important;",
`data-restore` = restoredValue
)

View File

@@ -11,22 +11,22 @@
#' @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). If
#' this argument is provided, then `choiceNames` and `choiceValues`
#' must not be provided, and vice-versa. The values should be strings; other
#' types (such as logicals and numbers) will be coerced to strings.
#' @param selected The initially selected value (if not specified then defaults
#' to the first value)
#' this argument is provided, then `choiceNames` and `choiceValues` must not
#' be provided, and vice-versa. The values should be strings; other types
#' (such as logicals and numbers) will be coerced to strings.
#' @param selected The initially selected value. If not specified, then it
#' defaults to the first item in `choices`. To start with no items selected,
#' use `character(0)`.
#' @param inline If `TRUE`, render the choices inline (i.e. horizontally)
#' @return A set of radio buttons that can be added to a UI definition.
#' @param choiceNames,choiceValues List of names and values, respectively, that
#' are displayed to the user in the app and correspond to the each choice (for
#' this reason, `choiceNames` and `choiceValues` must have the same
#' length). If either of these arguments is provided, then the other
#' *must* be provided and `choices` *must not* be provided. The
#' advantage of using both of these over a named list for `choices` is
#' that `choiceNames` allows any type of UI object to be passed through
#' (tag objects, icons, HTML code, ...), instead of just simple text. See
#' Examples.
#' this reason, `choiceNames` and `choiceValues` must have the same length).
#' If either of these arguments is provided, then the other *must* be provided
#' and `choices` *must not* be provided. The advantage of using both of these
#' over a named list for `choices` is that `choiceNames` allows any type of UI
#' object to be passed through (tag objects, icons, HTML code, ...), instead
#' of just simple text. See Examples.
#'
#' @family input elements
#' @seealso [updateRadioButtons()]
@@ -82,7 +82,8 @@
#' }
#'
#' @section Server value:
#' A character string containing the value of the selected button.
#'
#' A character string containing the value of the selected button.
#'
#' @export
radioButtons <- function(inputId, label, choices = NULL, selected = NULL,

View File

@@ -12,6 +12,14 @@
#' name will be treated as a placeholder prompt. For example:
#' `selectInput("letter", "Letter", c("Choose one" = "", LETTERS))`
#'
#' **Performance note:** `selectInput()` and `selectizeInput()` can slow down
#' significantly when thousands of choices are used; with legacy browsers like
#' Internet Explorer, the user interface may hang for many seconds. For large
#' numbers of choices, Shiny offers a "server-side selectize" option that
#' massively improves performance and efficiency; see
#' [this selectize article](https://shiny.rstudio.com/articles/selectize.html)
#' on the Shiny Dev Center for details.
#'
#' @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
@@ -100,7 +108,7 @@ selectInput <- function(inputId, label, choices, selected = NULL,
id = inputId,
class = if (!selectize) "form-control",
size = size,
selectOptions(choices, selected)
selectOptions(choices, selected, inputId, selectize)
)
if (multiple)
selectTag$attribs$multiple <- "multiple"
@@ -125,16 +133,22 @@ firstChoice <- function(choices) {
}
# 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) {
# This returns a HTML string instead of tags for performance reasons.
selectOptions <- function(choices, selected = NULL, inputId, perfWarning = FALSE) {
if (length(choices) >= 1000) {
warning("The select input \"", inputId, "\" contains a large number of ",
"options; consider using server-side selectize for massively improved ",
"performance. See the Details section of the ?selectizeInput help topic.",
call. = FALSE)
}
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)
selectOptions(choice, selected, inputId, perfWarning)
)
} else {
@@ -183,24 +197,25 @@ selectizeInput <- function(inputId, ..., options = NULL, width = NULL) {
# given a select input and its id, selectize it
selectizeIt <- function(inputId, select, options, nonempty = FALSE) {
# Make sure accessibility plugin is included
if (!('selectize-plugin-a11y' %in% options$plugins)) {
options$plugins <- c(options$plugins, list('selectize-plugin-a11y'))
}
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')
))
)
selectizeDep <- selectizeDependency()
if ('drag_drop' %in% options$plugins) {
selectizeDep <- list(selectizeDep, htmlDependency(
'jqueryui', '1.12.1', c(href = 'shared/jqueryui'),
script = 'jquery-ui.min.js'
))
selectizeDep <- c(
selectizeDep,
htmlDependency(
'jqueryui',
'1.12.1',
c(href = 'shared/jqueryui'),
script = 'jquery-ui.min.js'
)
)
}
# Insert script on same level as <select> tag
@@ -218,10 +233,50 @@ selectizeIt <- function(inputId, select, options, nonempty = FALSE) {
}
selectizeVersion <- "0.12.4"
selectizeDependency <- function(theme) {
list(
htmlDependency(
"selectize-js",
selectizeVersion,
src = c(href = "shared/selectize"),
script = c(
"js/selectize.min.js",
# Accessibility plugin for screen readers (https://github.com/SLMNBJ/selectize-plugin-a11y):
"accessibility/js/selectize-plugin-a11y.min.js"
)
),
bootstraplib::bs_dependency_defer(selectizeCSS)
)
}
selectizeCSS <- function(theme) {
if (!is_bs_theme(theme)) {
return(htmlDependency(
name = "selectize-css",
version = selectizeVersion,
src = c(href = "shared/selectize"),
stylesheet = "css/selectize.bootstrap3.css"
))
}
scss_file <- system.file(
package = "shiny", "www/shared/selectize/scss",
if ("3" %in% bootstraplib::theme_version(theme)) {
"selectize.bootstrap3.scss"
} else {
"selectize.bootstrap4.scss"
}
)
bootstraplib::bs_dependency(
input = sass::sass_file(scss_file),
theme = theme,
name = "selectize",
version = selectizeVersion,
cache_key_extra = utils::packageVersion("shiny")
)
}
#' Select variables from a data frame

View File

@@ -79,8 +79,7 @@ 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)
{
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")
@@ -144,6 +143,7 @@ sliderInput <- function(inputId, label, min, max, value, step = NULL,
sliderProps <- dropNulls(list(
class = "js-range-slider",
id = inputId,
`data-skin` = "shiny",
`data-type` = if (length(value) > 1) "double",
`data-min` = formatNoSci(min),
`data-max` = formatNoSci(max),
@@ -205,20 +205,59 @@ sliderInput <- function(inputId, label, min, max, value, step = NULL,
)
}
dep <- list(
htmlDependency("ionrangeslider", "2.1.6", 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")
attachDependencies(sliderTag, ionRangeSliderDependency())
}
ionRangeSliderVersion <- "2.3.1"
ionRangeSliderDependency <- function() {
list(
# ion.rangeSlider also needs normalize.css, which is already included in Bootstrap.
htmlDependency(
"ionrangeslider-javascript", ionRangeSliderVersion,
src = c(href = "shared/ionrangeslider"),
script = "js/ion.rangeSlider.min.js"
),
htmlDependency("strftime", "0.9.2", c(href="shared/strftime"),
htmlDependency(
"strftime", "0.9.2",
src = c(href = "shared/strftime"),
script = "strftime-min.js"
),
bootstraplib::bs_dependency_defer(ionRangeSliderDependencyCSS)
)
}
ionRangeSliderDependencyCSS <- function(theme) {
if (!is_bs_theme(theme)) {
return(htmlDependency(
"ionrangeslider-css",
ionRangeSliderVersion,
src = c(href = "shared/ionrangeslider"),
stylesheet = "css/ion.rangeSlider.css"
))
}
# Remap some variable names for ionRangeSlider's scss
sass_input <- list(
list(
bg = "$input-bg",
fg = "$input-color",
accent = "$component-active-bg",
`font-family` = "$font-family-base"
),
sass::sass_file(
system.file(package = "shiny", "www/shared/ionrangeslider/scss/shiny.scss")
)
)
attachDependencies(sliderTag, dep)
bootstraplib::bs_dependency(
input = sass_input,
theme = theme,
name = "ionRangeSlider",
version = ionRangeSliderVersion,
cache_key_extra = utils::packageVersion("shiny")
)
}
hasDecimals <- function(value) {
@@ -226,7 +265,6 @@ hasDecimals <- function(value) {
return (!identical(value, truncatedValue))
}
# If step is NULL, use heuristic to set the step size.
findStepSize <- function(min, max, step) {
if (!is.null(step)) return(step)

View File

@@ -51,7 +51,8 @@ textAreaInput <- function(inputId, label, value = "", width = NULL, height = NUL
}
style <- paste(
if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
# The width is specified on the parent div.
if (!is.null(width)) paste0("width: ", "100%", ";"),
if (!is.null(height)) paste0("height: ", validateCssUnit(height), ";"),
if (!is.null(resize)) paste0("resize: ", resize, ";")
)
@@ -62,6 +63,7 @@ textAreaInput <- function(inputId, label, value = "", width = NULL, height = NUL
div(class = "form-group shiny-input-container",
shinyInputLabel(inputId, label),
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
tags$textarea(
id = inputId,
class = "form-control",

View File

@@ -3,6 +3,8 @@ shinyInputLabel <- function(inputId, label = NULL) {
label,
class = "control-label",
class = if (is.null(label)) "shiny-label-null",
# `id` attribute is required for `aria-labelledby` used by screen readers:
id = paste0(inputId, "-label"),
`for` = inputId
)
}

80
R/knitr.R Normal file
View File

@@ -0,0 +1,80 @@
#' 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
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.
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
knit_print.reactive <- function(x, ..., inline = FALSE) {
renderFunc <- if (inline) renderText else renderPrint
knitr::knit_print(renderFunc({
x()
}), inline = inline)
}

View File

@@ -14,7 +14,26 @@
# returns `NULL`, or an `httpResponse`.
#
## ------------------------------------------------------------------------
httpResponse <- function(status = 200,
#' Create an HTTP response object
#'
#' @param status HTTP status code for the response.
#' @param content_type The value for the `Content-Type` header.
#' @param content The body of the response, given as a single-element character
#' vector (will be encoded as UTF-8) or a raw vector.
#' @param headers A named list of additional headers to include. Do not include
#' `Content-Length` (as it is automatically calculated) or `Content-Type` (the
#' `content_type` argument is used instead).
#'
#' @examples
#' httpResponse(status = 405L,
#' content_type = "text/plain",
#' content = "The requested method was not allowed"
#' )
#'
#' @keywords internal
#' @export
httpResponse <- function(status = 200L,
content_type = "text/html; charset=UTF-8",
content = "",
headers = list()) {

View File

@@ -31,7 +31,6 @@ extract <- function(promise) {
#' @noRd
#' @export
`$.mockclientdata` <- function(x, name) {
if (name == "allowDataUriScheme") { return(TRUE) }
if (name == "pixelratio") { return(1) }
if (name == "url_protocol") { return("http:") }
if (name == "url_hostname") { return("mocksession") }
@@ -156,6 +155,7 @@ makeExtraMethods <- function() {
"sendInsertTab",
"sendInsertUI",
"sendModal",
"setCurrentTheme",
"sendNotification",
"sendProgress",
"sendRemoveTab",
@@ -167,12 +167,10 @@ makeExtraMethods <- function() {
), makeErrors(
`@uploadEnd` = "for internal use only",
`@uploadInit` = "for internal use only",
`@uploadieFinish` = "for internal use only",
createBookmarkObservers = "for internal use only",
dispatch = "for internal use only",
handleRequest = "for internal use only",
requestFlush = "for internal use only",
saveFileUrl = "for internal use only",
startTiming = "for internal use only",
wsClosed = "for internal use only"
))
@@ -249,6 +247,8 @@ MockShinySession <- R6Class(
#' @field user The username of an authenticated user. Always `NULL` for a
#' `MockShinySession`.
user = NULL,
#' @field options A list containing session-level shinyOptions.
options = NULL,
#' @description Create a new MockShinySession.
initialize = function() {
@@ -273,6 +273,10 @@ MockShinySession <- R6Class(
self$input <- .createReactiveValues(private$.input, readonly = TRUE)
self$token <- createUniqueId(16)
# Copy app-level options
self$options <- getCurrentAppState()$options
self$cache <- MemoryCache$new()
self$appcache <- MemoryCache$new()

View File

@@ -29,10 +29,16 @@ removeModal <- function(session = getDefaultReactiveDomain()) {
#' Create a modal dialog UI
#'
#' This creates the UI for a modal dialog, using Bootstrap's modal class. Modals
#' are typically used for showing important messages, or for presenting UI that
#' requires input from the user, such as a username and password input.
#' @description
#' `modalDialog()` creates the UI for a modal dialog, using Bootstrap's modal
#' class. Modals are typically used for showing important messages, or for
#' presenting UI that requires input from the user, such as a user name and
#' password input.
#'
#' `modalButton()` creates a button that will dismiss the dialog when clicked,
#' typically used when customising the `footer`.
#'
#' @inheritParams actionButton
#' @param ... UI elements for the body of the modal dialog box.
#' @param title An optional title for the dialog.
#' @param footer UI for footer. Use `NULL` for no footer.
@@ -41,7 +47,7 @@ removeModal <- function(session = getDefaultReactiveDomain()) {
#' @param easyClose If `TRUE`, the modal dialog can be dismissed by
#' clicking outside the dialog box, or be pressing the Escape key. If
#' `FALSE` (the default), the modal dialog can't be dismissed in those
#' ways; instead it must be dismissed by clicking on the dismiss button, or
#' ways; instead it must be dismissed by clicking on a `modalButton()`, or
#' from a call to [removeModal()] on the server.
#' @param fade If `FALSE`, the modal dialog will have no fade-in animation
#' (it will simply appear rather than fade in to view).
@@ -169,13 +175,8 @@ modalDialog <- function(..., title = NULL, footer = modalButton("Dismiss"),
)
}
#' Create a button for a modal dialog
#'
#' When clicked, a `modalButton` will dismiss the modal dialog.
#'
#' @inheritParams actionButton
#' @seealso [modalDialog()] for examples.
#' @export
#' @rdname modalDialog
modalButton <- function(label, icon = NULL) {
tags$button(type = "button", class = "btn btn-default",
`data-dismiss` = "modal", validateIcon(icon), label

View File

@@ -204,7 +204,7 @@ Progress <- R6Class(
#' 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
#' `setProgress`.
#' [setProgress()] or [incProgress()].
#' @param min The value that represents the starting point of the progress bar.
#' Must be less tham `max`. Default is 0.
#' @param max The value that represents the end of the progress bar. Must be
@@ -227,6 +227,7 @@ Progress <- R6Class(
#' @param value Single-element numeric vector; the value at which to set the
#' progress bar, relative to `min` and `max`.
#'
#' @return The result of `expr`.
#' @examples
#' ## Only run examples in interactive R sessions
#' if (interactive()) {

View File

@@ -231,6 +231,12 @@ reactiveVal <- function(value = NULL, label = NULL) {
#' @rdname freezeReactiveValue
#' @export
freezeReactiveVal <- function(x) {
if (getOption("shiny.deprecation.messages", TRUE) && getOption("shiny.deprecation.messages.freeze", TRUE)) {
rlang::warn(
"freezeReactiveVal() is soft-deprecated, and may be removed in a future version of Shiny. (See https://github.com/rstudio/shiny/issues/3063)",
.frequency = "once", .frequency_id = "freezeReactiveVal")
}
domain <- getDefaultReactiveDomain()
if (is.null(domain)) {
stop("freezeReactiveVal() must be called when a default reactive domain is active.")
@@ -357,7 +363,7 @@ ReactiveValues <- R6Class(
keyValue
},
set = function(key, value) {
set = function(key, value, force = FALSE) {
# if key exists
# if it is the same value, return
#
@@ -389,10 +395,8 @@ ReactiveValues <- R6Class(
key_exists <- .values$containsKey(key)
if (key_exists) {
if (.dedupe && identical(.values$get(key), value)) {
return(invisible())
}
if (key_exists && !isTRUE(force) && .dedupe && identical(.values$get(key), value)) {
return(invisible())
}
# set the value for better logging
@@ -469,10 +473,15 @@ ReactiveValues <- R6Class(
# Mark a value as frozen If accessed while frozen, a shiny.silent.error will
# be thrown.
freeze = function(key) {
freeze = function(key, invalidate = FALSE) {
domain <- getDefaultReactiveDomain()
rLog$freezeReactiveKey(.reactId, key, domain)
setMeta(key, "frozen", TRUE)
if (invalidate) {
# Force an invalidation
self$set(key, NULL, force = TRUE)
}
},
thaw = function(key) {
@@ -727,7 +736,10 @@ str.reactivevalues <- function(object, indent.str = " ", ...) {
#' thing that happens if `req(FALSE)` is called. The value is thawed
#' (un-frozen; accessing it will no longer raise an exception) when the current
#' reactive domain is flushed. In a Shiny application, this occurs after all of
#' the observers are executed.
#' the observers are executed. **NOTE:** We are considering deprecating
#' `freezeReactiveVal`, and `freezeReactiveValue` except when `x` is `input`.
#' If this affects your app, please let us know by leaving a comment on
#' [this GitHub issue](https://github.com/rstudio/shiny/issues/3063).
#'
#' @param x For `freezeReactiveValue`, a [reactiveValues()]
#' object (like `input`); for `freezeReactiveVal`, a
@@ -1377,35 +1389,34 @@ observe <- function(x, env=parent.frame(), quoted=FALSE, label=NULL,
#' already exist; if so, its value will be used as the initial value of the
#' reactive variable (or `NULL` if the variable did not exist).
#'
#' @param symbol A character string indicating the name of the variable that
#' should be made reactive
#' @param env The environment that will contain the reactive variable
#'
#' @param symbol Name of variable to make reactive, as a string.
#' @param env Environment in which to create binding. Expert use only.
#' @return None.
#'
#' @keywords internal
#' @examples
#' \dontrun{
#' reactiveConsole(TRUE)
#'
#' a <- 10
#' makeReactiveBinding("a")
#'
#' b <- reactive(a * -1)
#' observe(print(b()))
#'
#' a <- 20
#' }
#' a <- 30
#'
#' reactiveConsole(FALSE)
#' @export
makeReactiveBinding <- function(symbol, env = parent.frame()) {
if (exists(symbol, envir = env, inherits = FALSE)) {
initialValue <- env[[symbol]]
rm(list = symbol, envir = env, inherits = FALSE)
}
else
} else {
initialValue <- NULL
values <- reactiveValues(value = initialValue)
makeActiveBinding(symbol, env=env, fun=function(v) {
if (missing(v))
values$value
else
values$value <- v
})
}
val <- reactiveVal(initialValue, label = symbol)
makeActiveBinding(symbol, val, env = env)
invisible()
}
@@ -1441,6 +1452,29 @@ setAutoflush <- local({
}
})
#' Activate reactivity in the console
#'
#' This is an experimental feature that allows you to enable reactivity
#' at the console, for the purposes of experimentation and learning.
#'
#' @keywords internal
#' @param enabled Turn console reactivity on or off?
#' @export
#' @examples
#' reactiveConsole(TRUE)
#' x <- reactiveVal(10)
#' y <- observe({
#' message("The value of x is ", x())
#' })
#' x(20)
#' x(30)
#' reactiveConsole(FALSE)
reactiveConsole <- function(enabled) {
options(shiny.suppressMissingContextError = enabled)
setAutoflush(enabled)
}
# ---------------------------------------------------------------------------
#' Timer

View File

@@ -150,6 +150,8 @@
#' `"app"` (the default), `"session"`, or a cache object like
#' a [diskCache()]. See the Cache Scoping section for more
#' information.
#' @param width,height not used. They are specified via the argument
#' `sizePolicy`.
#'
#' @seealso See [renderPlot()] for the regular, non-cached version of
#' this function. For more about configuring caches, see
@@ -295,7 +297,10 @@ renderCachedPlot <- function(expr,
res = 72,
cache = "app",
...,
outputArgs = list()
alt = "Plot object",
outputArgs = list(),
width = NULL,
height = NULL
) {
# This ..stacktraceon is matched by a ..stacktraceoff.. when plotFunc
@@ -307,6 +312,11 @@ renderCachedPlot <- function(expr,
args <- list(...)
if (!is.null(width) || !is.null(height)) {
warning("Unused argument(s) 'width' and/or 'height'. ",
"'sizePolicy' is used instead.")
}
cacheKeyExpr <- substitute(cacheKeyExpr)
# The real cache key we'll use also includes width, height, res, pixelratio.
# This is just the part supplied by the user.
@@ -341,6 +351,14 @@ renderCachedPlot <- function(expr,
# values get filled by an observer below.
fitDims <- reactiveValues(width = NULL, height = NULL)
# Make sure alt param to be reactive function
if (is.reactive(alt))
altWrapper <- alt
else if (is.function(alt))
altWrapper <- reactive({ alt() })
else
altWrapper <- function() { alt }
resizeObserver <- NULL
ensureResizeObserver <- function() {
if (!is.null(resizeObserver))
@@ -387,6 +405,8 @@ renderCachedPlot <- function(expr,
isolate({
width <- fitDims$width
height <- fitDims$height
# Make sure alt text to be reactive function
alt <- altWrapper()
})
pixelratio <- session$clientData$pixelratio %OR% 1
@@ -398,6 +418,7 @@ renderCachedPlot <- function(expr,
func = isolatedFunc,
width = width,
height = height,
alt = alt,
pixelratio = pixelratio,
res = res
),
@@ -434,6 +455,7 @@ renderCachedPlot <- function(expr,
function(userCacheKeyResult) {
width <- fitDims$width
height <- fitDims$height
alt <- altWrapper()
pixelratio <- session$clientData$pixelratio %OR% 1
key <- digest::digest(list(outputName, userCacheKeyResult, width, height, res, pixelratio), "xxhash64")
@@ -449,6 +471,7 @@ renderCachedPlot <- function(expr,
plotObj = plotObj,
width = width,
height = height,
alt = alt,
pixelratio = pixelratio
))
}
@@ -471,6 +494,7 @@ renderCachedPlot <- function(expr,
plotObj = drawReactiveResult,
width = width,
height = height,
alt = alt,
pixelratio = pixelratio
)
}
@@ -480,6 +504,7 @@ renderCachedPlot <- function(expr,
hybrid_chain(possiblyAsyncResult, function(result) {
width <- result$width
height <- result$height
alt <- result$alt
pixelratio <- result$pixelratio
# Three possibilities when we get here:
@@ -500,6 +525,7 @@ renderCachedPlot <- function(expr,
result$plotObj,
width,
height,
alt,
pixelratio,
res
),

View File

@@ -36,6 +36,12 @@
#' @param res Resolution of resulting plot, in pixels per inch. This value is
#' passed to [grDevices::png()]. Note that this affects the resolution of PNG
#' rendering in R; it won't change the actual ppi of the browser.
#' @param alt Alternate text for the HTML `<img>` tag
#' if it cannot be displayed or viewed (i.e., the user uses a screen reader).
#' In addition to a character string, the value may be a reactive expression
#' (or a function referencing reactive values) that returns a character string.
#' NULL or "" is not recommended because those should be limited to decorative images
#' (the default is "Plot object").
#' @param ... Arguments to be passed through to [grDevices::png()].
#' These can be used to set the width, height, background color, etc.
#' @param env The environment in which to evaluate `expr`.
@@ -51,9 +57,10 @@
#' call to [plotOutput()] when `renderPlot` is used in an
#' interactive R Markdown document.
#' @export
renderPlot <- function(expr, width='auto', height='auto', res=72, ...,
env=parent.frame(), quoted=FALSE,
execOnResize=FALSE, outputArgs=list()
renderPlot <- function(expr, width = 'auto', height = 'auto', res = 72, ...,
alt = "Plot object",
env = parent.frame(), quoted = FALSE,
execOnResize = FALSE, outputArgs = list()
) {
# This ..stacktraceon is matched by a ..stacktraceoff.. when plotFunc
# is called
@@ -75,6 +82,13 @@ renderPlot <- function(expr, width='auto', height='auto', res=72, ...,
else
heightWrapper <- function() { height }
if (is.reactive(alt))
altWrapper <- alt
else if (is.function(alt))
altWrapper <- reactive({ alt() })
else
altWrapper <- function() { alt }
getDims <- function() {
width <- widthWrapper()
height <- heightWrapper()
@@ -112,6 +126,7 @@ renderPlot <- function(expr, width='auto', height='auto', res=72, ...,
func = func,
width = dims$width,
height = dims$height,
alt = altWrapper(),
pixelratio = pixelratio,
res = res
), args))
@@ -140,7 +155,7 @@ renderPlot <- function(expr, width='auto', height='auto', res=72, ...,
dims <- getDims()
pixelratio <- session$clientData$pixelratio %OR% 1
result <- do.call("resizeSavedPlot", c(
list(name, shinysession, result, dims$width, dims$height, pixelratio, res),
list(name, shinysession, result, dims$width, dims$height, altWrapper(), pixelratio, res),
args
))
@@ -159,12 +174,17 @@ renderPlot <- function(expr, width='auto', height='auto', res=72, ...,
markRenderFunction(outputFunc, renderFunc, outputArgs = outputArgs)
}
resizeSavedPlot <- function(name, session, result, width, height, pixelratio, res, ...) {
resizeSavedPlot <- function(name, session, result, width, height, alt, pixelratio, res, ...) {
if (result$img$width == width && result$img$height == height &&
result$pixelratio == pixelratio && result$res == res) {
return(result)
}
if (isNamespaceLoaded("showtext")) {
showtextOpts <- showtext::showtext_opts(dpi = res*pixelratio)
on.exit({showtext::showtext_opts(showtextOpts)}, add = TRUE)
}
coordmap <- NULL
outfile <- plotPNG(function() {
grDevices::replayPlot(result$recordedPlot)
@@ -176,6 +196,7 @@ resizeSavedPlot <- function(name, session, result, width, height, pixelratio, re
src = session$fileUrl(name, outfile, contentType = "image/png"),
width = width,
height = height,
alt = alt,
coordmap = coordmap,
error = attr(coordmap, "error", exact = TRUE)
)
@@ -183,7 +204,7 @@ resizeSavedPlot <- function(name, session, result, width, height, pixelratio, re
result
}
drawPlot <- function(name, session, func, width, height, pixelratio, res, ...) {
drawPlot <- function(name, session, func, width, height, alt, pixelratio, res, ...) {
# 1. Start PNG
# 2. Enable displaylist recording
# 3. Call user-defined func
@@ -206,7 +227,7 @@ drawPlot <- function(name, session, func, width, height, pixelratio, res, ...) {
# but it's worth noting that the option doesn't currently work with CairoPNG.
# https://github.com/yixuan/showtext/issues/33
showtextOpts <- if (isNamespaceLoaded("showtext")) {
showtext::showtext_opts(dpi = res)
showtext::showtext_opts(dpi = res*pixelratio)
} else {
NULL
}
@@ -267,6 +288,7 @@ drawPlot <- function(name, session, func, width, height, pixelratio, res, ...) {
src = session$fileUrl(name, outfile, contentType='image/png'),
width = width,
height = height,
alt = alt,
coordmap = result$coordmap,
# Get coordmap error message if present
error = attr(result$coordmap, "error", exact = TRUE)

564
R/runapp.R Normal file
View File

@@ -0,0 +1,564 @@
#' 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
#' `"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 `"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 `server.R`, plus, either `ui.R` or
#' a `www` directory that contains the file `index.html`.
#' \item A directory containing `app.R`.
#' \item An `.R` file containing a Shiny application, ending with an
#' expression that produces a Shiny app object.
#' \item A list with `ui` and `server` components.
#' \item A Shiny app object created by [shinyApp()].
#' }
#' @param port The TCP port that the application should listen on. If the
#' `port` is not specified, and the `shiny.port` option is set (with
#' `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 `shiny.host` option, if set, or `"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 `"showcase"`, shows application code and metadata from a
#' `DESCRIPTION` file in the application directory alongside the
#' application. If set to `"normal"`, displays the application normally.
#' Defaults to `"auto"`, which displays the application in the mode given
#' in its `DESCRIPTION` file, if any.
#' @param test.mode Should the application be launched in test mode? This is
#' only used for recording or running automated tests. Defaults to the
#' `shiny.testmode` option, or FALSE if the option is not set.
#'
#' @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()) {
#' options(device.ask.default = FALSE)
#'
#' # 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"),
test.mode=getOption('shiny.testmode', FALSE)) {
on.exit({
handlerManager$clear()
}, add = TRUE)
if (isRunning()) {
stop("Can't call `runApp()` from within `runApp()`. If your ",
"application code contains `runApp()`, please remove it.")
}
# Make warnings print immediately
# Set pool.scheduler to support pool package
ops <- options(
# Raise warn level to 1, but don't lower it
warn = max(1, getOption("warn", default = 1)),
pool.scheduler = scheduleTask
)
on.exit(options(ops), add = TRUE)
# ============================================================================
# Global onStart/onStop callbacks
# ============================================================================
# Invoke user-defined onStop callbacks, before the application's internal
# onStop callbacks.
on.exit({
.globals$onStopCallbacks$invoke()
.globals$onStopCallbacks <- Callbacks$new()
}, add = TRUE)
require(shiny)
# ============================================================================
# Convert to Shiny app object
# ============================================================================
appParts <- as.shiny.appobj(appDir)
# ============================================================================
# Initialize app state object
# ============================================================================
# This is so calls to getCurrentAppState() can be used to find (A) whether an
# app is running and (B), get options and data associated with the app.
initCurrentAppState(appParts)
on.exit(clearCurrentAppState(), add = TRUE)
# Any shinyOptions set after this point will apply to the current app only
# (and will not persist after the app stops).
# ============================================================================
# shinyOptions
# ============================================================================
# A unique identifier associated with this run of this application. It is
# shared across sessions.
shinyOptions(appToken = createUniqueId(8))
# Set up default cache for app.
if (is.null(getShinyOption("cache"))) {
shinyOptions(cache = MemoryCache$new())
}
# Extract appOptions (which is a list) and store them as shinyOptions, for
# this app. (This is the only place we have to store settings that are
# accessible both the UI and server portion of the app.)
applyCapturedAppOptions(appParts$appOptions)
# ============================================================================
# runApp options set via shinyApp(options = list(...))
# ============================================================================
# The lines below set some of the app's running options, which
# can be:
# - left unspecified (in which case the arguments' default
# values from `runApp` kick in);
# - passed through `shinyApp`
# - passed through `runApp` (this function)
# - passed through both `shinyApp` and `runApp` (the latter
# takes precedence)
#
# Matrix of possibilities:
# | IN shinyApp | IN runApp | result | check |
# |-------------|-----------|--------------|----------------------------------------------------------------------------------------------------------------------------------------|
# | no | no | use defaults | exhaust all possibilities: if it's missing (runApp does not specify); THEN if it's not in shinyApp appParts$options; THEN use defaults |
# | yes | no | use shinyApp | if it's missing (runApp does not specify); THEN if it's in shinyApp appParts$options; THEN use shinyApp |
# | no | yes | use runApp | if it's not missing (runApp specifies), use those |
# | yes | yes | use runApp | if it's not missing (runApp specifies), use those |
#
# I tried to make this as compact and intuitive as possible,
# given that there are four distinct possibilities to check
appOps <- appParts$options
findVal <- function(arg, default) {
if (arg %in% names(appOps)) appOps[[arg]] else default
}
if (missing(port))
port <- findVal("port", port)
if (missing(launch.browser))
launch.browser <- findVal("launch.browser", launch.browser)
if (missing(host))
host <- findVal("host", host)
if (missing(quiet))
quiet <- findVal("quiet", quiet)
if (missing(display.mode))
display.mode <- findVal("display.mode", display.mode)
if (missing(test.mode))
test.mode <- findVal("test.mode", test.mode)
if (is.null(host) || is.na(host)) host <- '0.0.0.0'
# ============================================================================
# Hosted environment
# ============================================================================
workerId(workerId)
if (inShinyServer()) {
# 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!')
}
}
# ============================================================================
# Shinytest
# ============================================================================
# Set the testmode shinyoption so that this can be read by both the
# ShinySession and the UI code (which executes separately from the
# ShinySession code).
shinyOptions(testmode = test.mode)
if (test.mode) {
message("Running application in test mode.")
}
# ============================================================================
# Showcase mode
# ============================================================================
# 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 ("IncludeWWW" %in% colnames(settings)) {
.globals$IncludeWWW <- as.logical(settings[1, "IncludeWWW"])
if (is.na(.globals$IncludeWWW)) {
stop("In your Description file, `IncludeWWW` ",
"must be set to `True` (default) or `False`")
}
} else {
.globals$IncludeWWW <- TRUE
}
}
}
}
}
## default is to show the .js, .css and .html files in the www directory
## (if not in showcase mode, this variable will simply be ignored)
if (is.null(.globals$IncludeWWW) || is.na(.globals$IncludeWWW)) {
.globals$IncludeWWW <- TRUE
}
# 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)
}
# ============================================================================
# Server port
# ============================================================================
# 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
while (TRUE) {
port <- p_randomInt(3000, 8000)
# Reject ports in this range that are considered unsafe by Chrome
# http://superuser.com/questions/188058/which-ports-are-considered-unsafe-on-chrome
# https://github.com/rstudio/shiny/issues/1784
if (!port %in% c(3659, 4045, 6000, 6665:6669, 6697)) {
break
}
}
}
# 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
}
}
}
# ============================================================================
# onStart/onStop callbacks
# ============================================================================
# Set up the onStop before we call onStart, so that it gets called even if an
# error happens in onStart.
if (!is.null(appParts$onStop))
on.exit(appParts$onStop(), add = TRUE)
if (!is.null(appParts$onStart))
appParts$onStart()
# ============================================================================
# Start/stop httpuv app
# ============================================================================
server <- startApp(appParts, port, host, quiet)
# Make the httpuv server object accessible. Needed for calling
# addResourcePath while app is running.
shinyOptions(server = server)
on.exit({
stopServer(server)
}, add = TRUE)
# ============================================================================
# Launch web browser
# ============================================================================
if (!is.character(port)) {
browseHost <- host
if (identical(host, "0.0.0.0")) {
# http://0.0.0.0/ doesn't work on QtWebKit (i.e. RStudio viewer)
browseHost <- "127.0.0.1"
} else if (identical(host, "::")) {
browseHost <- "::1"
}
if (httpuv::ipFamily(browseHost) == 6L) {
browseHost <- paste0("[", browseHost, "]")
}
appUrl <- paste("http://", browseHost, ":", port, sep="")
if (is.function(launch.browser))
launch.browser(appUrl)
else if (launch.browser)
utils::browseURL(appUrl)
} else {
appUrl <- NULL
}
# ============================================================================
# Application hooks
# ============================================================================
callAppHook("onAppStart", appUrl)
on.exit({
callAppHook("onAppStop", appUrl)
}, add = TRUE)
# ============================================================================
# Run event loop via httpuv
# ============================================================================
.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) {
..stacktracefloor..(serviceApp())
}
})
)
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
#' [runApp()].
#'
#' @param returnValue The value that should be returned from
#' [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 `NA` (the default) to
#' list the available examples.
#' @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 `shiny.host` option, if set, or `"127.0.0.1"` if not.
#' @param display.mode The mode in which to display the example. Defaults to
#' `showcase`, but may be set to `normal` to see the example without
#' code or commentary.
#' @inheritParams runApp
#'
#' @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=getOption("shiny.port"),
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 `runApp`, but handles `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
#' [`shinyApp()`][shiny] et al, or, a UI object.
#' @param server Ignored if `app` is a Shiny app object; otherwise, passed
#' along to `shinyApp` (i.e. `shinyApp(ui = app, server = server)`).
#' @param port See [`runApp()`][shiny].
#' @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
#' [viewer()] functions.
#' @param stopOnCancel If `TRUE` (the default), then an `observeEvent`
#' is automatically created that handles `input$cancel` by calling
#' `stopApp()` with an error. Pass `FALSE` if you want to handle
#' `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
}

View File

@@ -5,14 +5,15 @@ inputHandlers <- Map$new()
#'
#' 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 `input`
#' variable of the `server.R` file.
#' deserialized by jsonlite) before making it available in the `input` variable
#' of the `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 `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".
#' the format of "packageName.widgetName". It should be called from the
#' package's `.onLoad()` function.
#'
#' Currently Shiny registers the following handlers: `shiny.matrix`,
#' `shiny.number`, and `shiny.date`.
@@ -20,23 +21,20 @@ inputHandlers <- Map$new()
#' The `type` of a custom Shiny Input widget will be deduced using the
#' `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.
#' 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
#' `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 `shinysession` in which the input exists.}
#' \item{The name of the input.}
#' }
#' @param force If `TRUE`, will overwrite any existing handler without
#' warning. If `FALSE`, will throw an error if this class already has
#' a handler defined.
#' parameters: \enumerate{ \item{The value of this input as provided by the
#' client, deserialized using jsonlite.} \item{The `shinysession` in which the
#' input exists.} \item{The name of the input.} }
#' @param force If `TRUE`, will overwrite any existing handler without warning.
#' If `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
#' # In a package, this should be called from the .onLoad function.
#' registerInputHandler("mypackage.validint", function(x, shinysession, name) {
#' if (is.null(x)) return(NA)
#' round(x)

169
R/server-resource-paths.R Normal file
View File

@@ -0,0 +1,169 @@
.globals$resourcePaths <- list()
.globals$resources <- list()
#' Resource Publishing
#'
#' Add, remove, or list directory of static resources to Shiny's web server,
#' with the given path prefix. Primarily intended for package authors to make
#' supporting JavaScript/CSS files available to their components.
#'
#' Shiny provides two ways of serving static files (i.e., resources):
#'
#' 1. Static files under the `www/` directory are automatically made available
#' under a request path that begins with `/`.
#' 2. `addResourcePath()` makes static files in a `directoryPath` available
#' under a request path that begins with `prefix`.
#'
#' The second approach is primarily intended for package authors to make
#' supporting JavaScript/CSS files available to their components.
#'
#' Tools for managing static resources published by Shiny's web server:
#' * `addResourcePath()` adds a directory of static resources.
#' * `resourcePaths()` lists the currently active resource mappings.
#' * `removeResourcePath()` removes a directory of static resources.
#'
#' @param prefix The URL prefix (without slashes). Valid characters are a-z,
#' A-Z, 0-9, hyphen, period, and underscore. For example, a value of 'foo'
#' means that any request paths that begin with '/foo' will be mapped to the
#' given directory.
#' @param directoryPath The directory that contains the static resources to be
#' served.
#'
#' @rdname resourcePaths
#' @seealso [singleton()]
#'
#' @examples
#' addResourcePath('datasets', system.file('data', package='datasets'))
#' resourcePaths()
#' removeResourcePath('datasets')
#' resourcePaths()
#'
#' # make sure all resources are removed
#' lapply(names(resourcePaths()), removeResourcePath)
#' @export
addResourcePath <- function(prefix, directoryPath) {
if (length(prefix) != 1) stop("prefix must be of length 1")
if (grepl("^\\.+$", prefix)) stop("prefix can't be composed of dots only")
if (!grepl('[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")
}
normalizedPath <- tryCatch(normalizePath(directoryPath, mustWork = TRUE),
error = function(e) {
stop("Couldn't normalize path in `addResourcePath`, with arguments: ",
"`prefix` = '", prefix, "'; `directoryPath` = '" , directoryPath, "'")
}
)
# # Often times overwriting a resource path is "what you want",
# # but sometimes it can lead to difficult to diagnose issues
# # (e.g. an implict dependency might set a resource path that
# # conflicts with what you, the app author, are trying to register)
# # Note that previous versions of shiny used to warn about this case,
# # but it was eventually removed since it caused confusion (#567).
# # It seems a good compromise is to throw a more information message.
# if (getOption("shiny.resourcePathChanges", FALSE) &&
# prefix %in% names(.globals$resourcePaths)) {
# existingPath <- .globals$resourcePaths[[prefix]]$path
# if (normalizedPath != existingPath) {
# message(
# "The resource path '", prefix, "' used to point to ",
# existingPath, ", but it now points to ", normalizedPath, ". ",
# "If your app doesn't work as expected, you may want to ",
# "choose a different prefix name."
# )
# }
# }
# If a shiny app is currently running, dynamically register this path with
# the corresponding httpuv server object.
if (!is.null(getShinyOption("server")))
{
getShinyOption("server")$setStaticPath(.list = stats::setNames(normalizedPath, prefix))
}
# .globals$resourcePaths and .globals$resources persist across runs of applications.
.globals$resourcePaths[[prefix]] <- staticPath(normalizedPath)
# This is necessary because resourcePaths is only for serving assets out of C++;
# to support subapps, we also need assets to be served out of R, because those
# URLs are rewritten by R code (i.e. routeHandler) before they can be matched to
# a resource path.
.globals$resources[[prefix]] <- list(
directoryPath = normalizedPath,
func = staticHandler(normalizedPath)
)
}
#' @rdname resourcePaths
#' @export
resourcePaths <- function() {
urls <- names(.globals$resourcePaths)
paths <- vapply(.globals$resourcePaths, function(x) x$path, character(1))
stats::setNames(paths, urls)
}
hasResourcePath <- function(prefix) {
prefix %in% names(resourcePaths())
}
#' @rdname resourcePaths
#' @export
removeResourcePath <- function(prefix) {
if (length(prefix) > 1) stop("`prefix` must be of length 1.")
if (!hasResourcePath(prefix)) {
warning("Resource ", prefix, " not found.")
return(invisible(FALSE))
}
.globals$resourcePaths[[prefix]] <- NULL
.globals$resources[[prefix]] <- NULL
invisible(TRUE)
}
# This function handles any GET request with two or more path elements where the
# first path element matches a prefix that was previously added using
# addResourcePath().
#
# For example, if `addResourcePath("foo", "~/bar")` was called, then a GET
# request for /foo/one/two.html would rewrite the PATH_INFO as /one/two.html and
# send it to the resource path function for "foo". As of this writing, that
# function will always be a staticHandler, which serves up a file if it exists
# and NULL if it does not.
#
# Since Shiny 1.3.x, assets registered via addResourcePath should mostly be
# served out of httpuv's native static file serving features. However, in the
# specific case of subapps, the R code path must be used, because subapps insert
# a giant random ID into the beginning of the URL that must be stripped off by
# an R route handler (see addSubApp()).
resourcePathHandler <- function(req) {
if (!identical(req$REQUEST_METHOD, 'GET'))
return(NULL)
# e.g. "/foo/one/two.html"
path <- req$PATH_INFO
match <- regexpr('^/([^/]+)/', path, perl=TRUE)
if (match == -1)
return(NULL)
len <- attr(match, 'capture.length')
# e.g. "foo"
prefix <- substr(path, 2, 2 + len - 1)
resInfo <- .globals$resources[[prefix]]
if (is.null(resInfo))
return(NULL)
# e.g. "/one/two.html"
suffix <- substr(path, 2 + len, nchar(path))
# Create a new request that's a clone of the current request, but adjust
# PATH_INFO and SCRIPT_NAME to reflect that we have already matched the first
# path element (e.g. "/foo"). See routeHandler() for more info.
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))
}

View File

@@ -22,180 +22,10 @@ registerClient <- function(client) {
}
.globals$resourcePaths <- list()
.globals$resources <- list()
.globals$showcaseDefault <- 0
.globals$showcaseOverride <- FALSE
#' Resource Publishing
#'
#' Add, remove, or list directory of static resources to Shiny's web server,
#' with the given path prefix. Primarily intended for package authors to make
#' supporting JavaScript/CSS files available to their components.
#'
#' Shiny provides two ways of serving static files (i.e., resources):
#'
#' 1. Static files under the `www/` directory are automatically made available
#' under a request path that begins with `/`.
#' 2. `addResourcePath()` makes static files in a `directoryPath` available
#' under a request path that begins with `prefix`.
#'
#' The second approach is primarily intended for package authors to make
#' supporting JavaScript/CSS files available to their components.
#'
#' Tools for managing static resources published by Shiny's web server:
#' * `addResourcePath()` adds a directory of static resources.
#' * `resourcePaths()` lists the currently active resource mappings.
#' * `removeResourcePath()` removes a directory of static resources.
#'
#' @param prefix The URL prefix (without slashes). Valid characters are a-z,
#' A-Z, 0-9, hyphen, period, and underscore. For example, a value of 'foo'
#' means that any request paths that begin with '/foo' will be mapped to the
#' given directory.
#' @param directoryPath The directory that contains the static resources to be
#' served.
#'
#' @rdname resourcePaths
#' @seealso [singleton()]
#'
#' @examples
#' addResourcePath('datasets', system.file('data', package='datasets'))
#' resourcePaths()
#' removeResourcePath('datasets')
#' resourcePaths()
#'
#' # make sure all resources are removed
#' lapply(names(resourcePaths()), removeResourcePath)
#' @export
addResourcePath <- function(prefix, directoryPath) {
if (length(prefix) != 1) stop("prefix must be of length 1")
if (!grepl('^[a-z0-9\\-_][a-z0-9\\-_.]*$', prefix, ignore.case = TRUE, perl = TRUE)) {
stop("addResourcePath called with invalid prefix; please see documentation")
}
if (prefix %in% c('shared')) {
stop("addResourcePath called with the reserved prefix '", prefix, "'; ",
"please use a different prefix")
}
normalizedPath <- tryCatch(normalizePath(directoryPath, mustWork = TRUE),
error = function(e) {
stop("Couldn't normalize path in `addResourcePath`, with arguments: ",
"`prefix` = '", prefix, "'; `directoryPath` = '" , directoryPath, "'")
}
)
# # Often times overwriting a resource path is "what you want",
# # but sometimes it can lead to difficult to diagnose issues
# # (e.g. an implict dependency might set a resource path that
# # conflicts with what you, the app author, are trying to register)
# # Note that previous versions of shiny used to warn about this case,
# # but it was eventually removed since it caused confusion (#567).
# # It seems a good compromise is to throw a more information message.
# if (getOption("shiny.resourcePathChanges", FALSE) &&
# prefix %in% names(.globals$resourcePaths)) {
# existingPath <- .globals$resourcePaths[[prefix]]$path
# if (normalizedPath != existingPath) {
# message(
# "The resource path '", prefix, "' used to point to ",
# existingPath, ", but it now points to ", normalizedPath, ". ",
# "If your app doesn't work as expected, you may want to ",
# "choose a different prefix name."
# )
# }
# }
# If a shiny app is currently running, dynamically register this path with
# the corresponding httpuv server object.
if (!is.null(getShinyOption("server")))
{
getShinyOption("server")$setStaticPath(.list = stats::setNames(normalizedPath, prefix))
}
# .globals$resourcePaths and .globals$resources persist across runs of applications.
.globals$resourcePaths[[prefix]] <- staticPath(normalizedPath)
# This is necessary because resourcePaths is only for serving assets out of C++;
# to support subapps, we also need assets to be served out of R, because those
# URLs are rewritten by R code (i.e. routeHandler) before they can be matched to
# a resource path.
.globals$resources[[prefix]] <- list(
directoryPath = normalizedPath,
func = staticHandler(normalizedPath)
)
}
#' @rdname resourcePaths
#' @export
resourcePaths <- function() {
urls <- names(.globals$resourcePaths)
paths <- vapply(.globals$resourcePaths, function(x) x$path, character(1))
stats::setNames(paths, urls)
}
hasResourcePath <- function(prefix) {
prefix %in% names(resourcePaths())
}
#' @rdname resourcePaths
#' @export
removeResourcePath <- function(prefix) {
if (length(prefix) > 1) stop("`prefix` must be of length 1.")
if (!hasResourcePath(prefix)) {
warning("Resource ", prefix, " not found.")
return(invisible(FALSE))
}
.globals$resourcePaths[[prefix]] <- NULL
.globals$resources[[prefix]] <- NULL
invisible(TRUE)
}
# This function handles any GET request with two or more path elements where the
# first path element matches a prefix that was previously added using
# addResourcePath().
#
# For example, if `addResourcePath("foo", "~/bar")` was called, then a GET
# request for /foo/one/two.html would rewrite the PATH_INFO as /one/two.html and
# send it to the resource path function for "foo". As of this writing, that
# function will always be a staticHandler, which serves up a file if it exists
# and NULL if it does not.
#
# Since Shiny 1.3.x, assets registered via addResourcePath should mostly be
# served out of httpuv's native static file serving features. However, in the
# specific case of subapps, the R code path must be used, because subapps insert
# a giant random ID into the beginning of the URL that must be stripped off by
# an R route handler (see addSubApp()).
resourcePathHandler <- function(req) {
if (!identical(req$REQUEST_METHOD, 'GET'))
return(NULL)
# e.g. "/foo/one/two.html"
path <- req$PATH_INFO
match <- regexpr('^/([^/]+)/', path, perl=TRUE)
if (match == -1)
return(NULL)
len <- attr(match, 'capture.length')
# e.g. "foo"
prefix <- substr(path, 2, 2 + len - 1)
resInfo <- .globals$resources[[prefix]]
if (is.null(resInfo))
return(NULL)
# e.g. "/one/two.html"
suffix <- substr(path, 2 + len, nchar(path))
# Create a new request that's a clone of the current request, but adjust
# PATH_INFO and SCRIPT_NAME to reflect that we have already matched the first
# path element (e.g. "/foo"). See routeHandler() for more info.
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
#'
@@ -644,9 +474,6 @@ serviceApp <- function() {
.shinyServerMinVersion <- '0.3.4'
# Global flag that's TRUE whenever we're inside of the scope of a call to runApp
.globals$running <- FALSE
#' Check whether a Shiny application is running
#'
#' This function tests whether a Shiny application is currently running.
@@ -655,589 +482,9 @@ serviceApp <- function() {
#' `FALSE`.
#' @export
isRunning <- function() {
.globals$running
!is.null(getCurrentAppState())
}
#' 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
#' `"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 `"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 `server.R`, plus, either `ui.R` or
#' a `www` directory that contains the file `index.html`.
#' \item A directory containing `app.R`.
#' \item An `.R` file containing a Shiny application, ending with an
#' expression that produces a Shiny app object.
#' \item A list with `ui` and `server` components.
#' \item A Shiny app object created by [shinyApp()].
#' }
#' @param port The TCP port that the application should listen on. If the
#' `port` is not specified, and the `shiny.port` option is set (with
#' `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 `shiny.host` option, if set, or `"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 `"showcase"`, shows application code and metadata from a
#' `DESCRIPTION` file in the application directory alongside the
#' application. If set to `"normal"`, displays the application normally.
#' Defaults to `"auto"`, which displays the application in the mode given
#' in its `DESCRIPTION` file, if any.
#' @param test.mode Should the application be launched in test mode? This is
#' only used for recording or running automated tests. Defaults to the
#' `shiny.testmode` option, or FALSE if the option is not set.
#'
#' @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()) {
#' options(device.ask.default = FALSE)
#'
#' # 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"),
test.mode=getOption('shiny.testmode', FALSE)) {
on.exit({
handlerManager$clear()
}, add = TRUE)
if (.globals$running) {
stop("Can't call `runApp()` from within `runApp()`. If your ",
"application code contains `runApp()`, please remove it.")
}
.globals$running <- TRUE
on.exit({
.globals$running <- FALSE
}, add = TRUE)
# Enable per-app Shiny options, for shinyOptions() and getShinyOption().
oldOptionSet <- .globals$options
on.exit({
.globals$options <- oldOptionSet
},add = TRUE)
# A unique identifier associated with this run of this application. It is
# shared across sessions.
shinyOptions(appToken = createUniqueId(8))
# Make warnings print immediately
# Set pool.scheduler to support pool package
ops <- options(
# Raise warn level to 1, but don't lower it
warn = max(1, getOption("warn", default = 1)),
pool.scheduler = scheduleTask
)
on.exit(options(ops), add = TRUE)
# Set up default cache for app.
if (is.null(getShinyOption("cache"))) {
shinyOptions(cache = MemoryCache$new())
}
appParts <- as.shiny.appobj(appDir)
# The lines below set some of the app's running options, which
# can be:
# - left unspeficied (in which case the arguments' default
# values from `runApp` kick in);
# - passed through `shinyApp`
# - passed through `runApp` (this function)
# - passed through both `shinyApp` and `runApp` (the latter
# takes precedence)
#
# Matrix of possibilities:
# | IN shinyApp | IN runApp | result | check |
# |-------------|-----------|--------------|----------------------------------------------------------------------------------------------------------------------------------------|
# | no | no | use defaults | exhaust all possibilities: if it's missing (runApp does not specify); THEN if it's not in shinyApp appParts$options; THEN use defaults |
# | yes | no | use shinyApp | if it's missing (runApp does not specify); THEN if it's in shinyApp appParts$options; THEN use shinyApp |
# | no | yes | use runApp | if it's not missing (runApp specifies), use those |
# | yes | yes | use runApp | if it's not missing (runApp specifies), use those |
#
# I tried to make this as compact and intuitive as possible,
# given that there are four distinct possibilities to check
appOps <- appParts$options
findVal <- function(arg, default) {
if (arg %in% names(appOps)) appOps[[arg]] else default
}
if (missing(port))
port <- findVal("port", port)
if (missing(launch.browser))
launch.browser <- findVal("launch.browser", launch.browser)
if (missing(host))
host <- findVal("host", host)
if (missing(quiet))
quiet <- findVal("quiet", quiet)
if (missing(display.mode))
display.mode <- findVal("display.mode", display.mode)
if (missing(test.mode))
test.mode <- findVal("test.mode", test.mode)
if (is.null(host) || is.na(host)) host <- '0.0.0.0'
workerId(workerId)
if (inShinyServer()) {
# 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)
.globals$testMode <- test.mode
if (test.mode) {
message("Running application in test mode.")
}
# 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 ("IncludeWWW" %in% colnames(settings)) {
.globals$IncludeWWW <- as.logical(settings[1, "IncludeWWW"])
if (is.na(.globals$IncludeWWW)) {
stop("In your Description file, `IncludeWWW` ",
"must be set to `True` (default) or `False`")
}
} else {
.globals$IncludeWWW <- TRUE
}
}
}
}
}
## default is to show the .js, .css and .html files in the www directory
## (if not in showcase mode, this variable will simply be ignored)
if (is.null(.globals$IncludeWWW) || is.na(.globals$IncludeWWW)) {
.globals$IncludeWWW <- TRUE
}
# 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
while (TRUE) {
port <- p_randomInt(3000, 8000)
# Reject ports in this range that are considered unsafe by Chrome
# http://superuser.com/questions/188058/which-ports-are-considered-unsafe-on-chrome
# https://github.com/rstudio/shiny/issues/1784
if (!port %in% c(3659, 4045, 6000, 6665:6669, 6697)) {
break
}
}
}
# 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
}
}
}
# Invoke user-defined onStop callbacks, before the application's internal
# onStop callbacks.
on.exit({
.globals$onStopCallbacks$invoke()
.globals$onStopCallbacks <- Callbacks$new()
}, add = TRUE)
# Extract appOptions (which is a list) and store them as shinyOptions, for
# this app. (This is the only place we have to store settings that are
# accessible both the UI and server portion of the app.)
unconsumeAppOptions(appParts$appOptions)
# Set up the onStop before we call onStart, so that it gets called even if an
# error happens in onStart.
if (!is.null(appParts$onStop))
on.exit(appParts$onStop(), add = TRUE)
if (!is.null(appParts$onStart))
appParts$onStart()
server <- startApp(appParts, port, host, quiet)
# Make the httpuv server object accessible. Needed for calling
# addResourcePath while app is running.
shinyOptions(server = server)
on.exit({
stopServer(server)
}, add = TRUE)
if (!is.character(port)) {
browseHost <- host
if (identical(host, "0.0.0.0")) {
# http://0.0.0.0/ doesn't work on QtWebKit (i.e. RStudio viewer)
browseHost <- "127.0.0.1"
} else if (identical(host, "::")) {
browseHost <- "::1"
}
if (httpuv::ipFamily(browseHost) == 6L) {
browseHost <- paste0("[", browseHost, "]")
}
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) {
..stacktracefloor..(serviceApp())
}
})
)
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
#' [runApp()].
#'
#' @param returnValue The value that should be returned from
#' [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 `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 `shiny.host` option, if set, or `"127.0.0.1"` if not.
#' @param display.mode The mode in which to display the example. Defaults to
#' `showcase`, but may be set to `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 `runApp`, but handles `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
#' [`shinyApp()`][shiny] et al, or, a UI object.
#' @param server Ignored if `app` is a Shiny app object; otherwise, passed
#' along to `shinyApp` (i.e. `shinyApp(ui = app, server = server)`).
#' @param port See [`runApp()`][shiny].
#' @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
#' [viewer()] functions.
#' @param stopOnCancel If `TRUE` (the default), then an `observeEvent`
#' is automatically created that handles `input$cancel` by calling
#' `stopApp()` with an error. Pass `FALSE` if you want to handle
#' `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
#' [utils::browseURL()]).
#'
#' @return A function that takes a single `url` parameter, suitable for
#' passing as the `viewer` argument of [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 `NULL`, use the existing viewer pane
#' size. If `"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 [utils::browseURL()].
#' @rdname viewer
#' @export
browserViewer <- function(browser = getOption("browser")) {
function(url) {
utils::browseURL(url, browser = browser)
}
}
# Returns TRUE if we're running in Shiny Server or other hosting environment,
# otherwise returns FALSE.

View File

@@ -8,31 +8,55 @@ getShinyOption <- function(name, default = NULL) {
# Make sure to use named (not numeric) indexing
name <- as.character(name)
if (name %in% names(.globals$options))
.globals$options[[name]]
else
default
# Check if there's a current session
session <- getDefaultReactiveDomain()
if (!is.null(session)) {
if (name %in% names(session$options)) {
return(session$options[[name]])
} else {
return(default)
}
}
# Check if there's a current app
app_state <- getCurrentAppState()
if (!is.null(app_state)) {
if (name %in% names(app_state$options)) {
return(app_state$options[[name]])
} else {
return(default)
}
}
# If we got here, look in global options
if (name %in% names(.globals$options)) {
return(.globals$options[[name]])
} else {
return(default)
}
}
#' Get or set Shiny options
#'
#' `getShinyOption()` retrieves the value of a Shiny option. `shinyOptions()`
#' sets the value of Shiny options; it can also be used to return a list of all
#' currently-set Shiny options.
#' @description
#'
#' @section Scope:
#' There is a global option set which is available by default. When a Shiny
#' application is run with [runApp()], that option set is duplicated and the
#' new option set is available for getting or setting values. If options
#' are set from `global.R`, `app.R`, `ui.R`, or `server.R`, or if they are set
#' from inside the server function, then the options will be scoped to the
#' application. When the application exits, the new option set is discarded and
#' the global option set is restored.
#' There are two mechanisms for working with options for Shiny. One is the
#' [options()] function, which is part of base R, and the other is the
#' `shinyOptions()` function, which is in the Shiny package. The reason for
#' these two mechanisms is has to do with legacy code and scoping.
#'
#' @section Options:
#' There are a number of global options that affect Shiny's behavior. These can
#' be set globally with `options()` or locally (for a single app) with
#' `shinyOptions()`.
#' The [options()] function sets options globally, for the duration of the R
#' process. The [getOption()] function retrieves the value of an option. All
#' shiny related options of this type are prefixed with `"shiny."`.
#'
#' The `shinyOptions()` function sets the value of a shiny option, but unlike
#' `options()`, it is not always global in scope; the options may be scoped
#' globally, to an application, or to a user session in an application,
#' depending on the context. The `getShinyOption()` function retrieves a value
#' of a shiny option. Currently, the options set via `shinyOptions` are for
#' internal use only.
#'
#' @section Options with `options()`:
#'
#' \describe{
#' \item{shiny.autoreload (defaults to `FALSE`)}{If `TRUE` when a Shiny app is launched, the
@@ -107,46 +131,119 @@ getShinyOption <- function(name, default = NULL) {
#' `"recv"` (only print messages received by the server), `TRUE`
#' (print all messages), or `FALSE` (default; don't print any of these
#' messages).}
#' \item{shiny.autoload.r (defaults to `TRUE`)}{If `TRUE`, then the R/
#' of a shiny app will automatically be sourced.}
#' \item{shiny.usecairo (defaults to `TRUE`)}{This is used to disable graphical rendering by the
#' Cairo package, if it is installed. See [plotPNG()] for more
#' information.}
#' }
#'
#'
#' @section Scoping for `shinyOptions()`:
#'
#' There are three levels of scoping for `shinyOptions()`: global,
#' application, and session.
#'
#' The global option set is available by default. Any calls to
#' `shinyOptions()` and `getShinyOption()` outside of an app will access the
#' global option set.
#'
#' When a Shiny application is run with [runApp()], the global option set is
#' duplicated and the new option set is available at the application level. If
#' options are set from `global.R`, `app.R`, `ui.R`, or `server.R` (but
#' outside of the server function), then the application-level options will be
#' modified.
#'
#' Each time a user session is started, the application-level option set is
#' duplicated, for that session. If the options are set from inside the server
#' function, then they will be scoped to the session.
#'
#' @section Options with `shinyOptions()`:
#'
#' There are a number of global options that affect Shiny's behavior. These
#' can be set globally with `options()` or locally (for a single app) with
#' `shinyOptions()`.
#'
#' \describe{ \item{cache}{A caching object that will be used by
#' [renderCachedPlot()]. If not specified, a [memoryCache()] will be used.} }
#'
#' @param ... Options to set, with the form `name = value`.
#' @aliases shiny-options
#' @examples
#' \dontrun{
#' shinyOptions(myOption = 10)
#' getShinyOption("myOption")
#' }
#' @export
shinyOptions <- function(...) {
newOpts <- list(...)
if (length(newOpts) > 0) {
# If we're within a session, modify at the session level.
session <- getDefaultReactiveDomain()
if (!is.null(session)) {
# Modify session-level-options
session$options <- dropNulls(mergeVectors(session$options, newOpts))
return(invisible(session$options))
}
# If not in a session, but we have a currently running app, modify options
# at the app level.
app_state <- getCurrentAppState()
if (!is.null(app_state)) {
# Modify app-level options
app_state$options <- dropNulls(mergeVectors(app_state$options, newOpts))
return(invisible(app_state$options))
}
# If no currently running app, modify global options and return them.
.globals$options <- dropNulls(mergeVectors(.globals$options, newOpts))
invisible(.globals$options)
} else {
.globals$options
return(invisible(.globals$options))
}
}
# If not setting any options, just return current option set, visibly.
# Eval an expression with a new option set
withLocalOptions <- function(expr) {
oldOptionSet <- .globals$options
on.exit(.globals$options <- oldOptionSet)
session <- getDefaultReactiveDomain()
if (!is.null(session)) {
return(session$options)
}
expr
app_state <- getCurrentAppState()
if (!is.null(app_state)) {
return(app_state$options)
}
return(.globals$options)
}
# Get specific shiny options and put them in a list, reset those shiny options,
# and then return the options list. This should be during the creation of a
# shiny app object, which happens before another option frame is added to the
# options stack (the new option frame is added when the app is run). This
# function "consumes" the options when the shinyApp object is created, so the
# options won't affect another app that is created later.
consumeAppOptions <- function() {
# shiny app object. This function "consumes" the options when the shinyApp
# object is created, so the options won't affect another app that is created
# later.
#
# ==== Example ====
# shinyOptions(bookmarkStore = 1234)
# # This now returns 1234.
# getShinyOption("bookmarkStore")
#
# # Creating the app captures the bookmarkStore option and clears it.
# s <- shinyApp(
# fluidPage(verbatimTextOutput("txt")),
# function(input, output) {
# output$txt <- renderText(getShinyOption("bookmarkStore"))
# }
# )
#
# # This now returns NULL.
# getShinyOption("bookmarkStore")
#
# When running the app, the app will display "1234"
# runApp(s)
#
# # After quitting the app, this still returns NULL.
# getShinyOption("bookmarkStore")
# ==================
#
# If another app had been created after s was created, but before s was run,
# then it would capture the value of "bookmarkStore" at the time of creation.
captureAppOptions <- function() {
options <- list(
appDir = getwd(),
bookmarkStore = getShinyOption("bookmarkStore")
@@ -157,9 +254,9 @@ consumeAppOptions <- function() {
options
}
# Do the inverse of consumeAppOptions. This should be called once the app is
# Do the inverse of captureAppOptions. This should be called once the app is
# started.
unconsumeAppOptions <- function(options) {
applyCapturedAppOptions <- function(options) {
if (!is.null(options)) {
do.call(shinyOptions, options)
}

144
R/shiny.R
View File

@@ -117,9 +117,6 @@ workerId <- local({
#' \item{clientData}{
#' A [reactiveValues()] object that contains information about the client.
#' \itemize{
#' \item{`allowDataUriScheme` is a logical value that indicates whether
#' the browser is able to handle URIs that use the `data:` scheme.
#' }
#' \item{`pixelratio` reports the "device pixel ratio" from the web browser,
#' or 1 if none is reported. The value is 2 for Apple Retina displays.
#' }
@@ -474,8 +471,22 @@ ShinySession <- R6Class(
if (!is.null(params$input)) {
allInputs <- isolate(
reactiveValuesToList(self$input, all.names = TRUE)
# The isolate and reactiveValuesToList calls are being executed
# in a non-reactive context, but will produce output in the reactlog
# Seeing new, unlabelled reactives ONLY when calling shinytest is
# jarring / frustrating to debug.
# Since labeling these values is not currently supported in reactlog,
# it is better to hide them.
# Hopefully we can replace this with something like
# `with_reactlog_group("shinytest", {})`, which would visibily explain
# why the new reactives are added when calling shinytest
withr::with_options(
list(shiny.reactlog = FALSE),
{
allInputs <- isolate(
reactiveValuesToList(self$input, all.names = TRUE)
)
}
)
# If params$input is "1", return all; otherwise return just the
@@ -651,6 +662,7 @@ ShinySession <- R6Class(
cache = NULL, # A cache object used in the session
user = NULL,
groups = NULL,
options = NULL, # For session-specific shinyOptions()
initialize = function(websocket) {
private$websocket <- websocket
@@ -681,6 +693,9 @@ ShinySession <- R6Class(
private$.outputs <- list()
private$.outputOptions <- list()
# Copy app-level options
self$options <- getCurrentAppState()$options
self$cache <- MemoryCache$new()
private$bookmarkCallbacks <- Callbacks$new()
@@ -688,7 +703,7 @@ ShinySession <- R6Class(
private$restoreCallbacks <- Callbacks$new()
private$restoredCallbacks <- Callbacks$new()
private$testMode <- .globals$testMode
private$testMode <- getShinyOption("testmode", default = FALSE)
private$enableTestSnapshot()
private$registerSessionEndCallbacks()
@@ -928,7 +943,33 @@ ShinySession <- R6Class(
impl <- .subset2(x, 'impl')
key <- .subset2(x, 'ns')(name)
impl$freeze(key)
is_input <- identical(impl, private$.input)
# There's no good reason for us not to just do force=TRUE, except that we
# know this fixes problems for freezeReactiveValue(input) but we don't
# currently even know what you would use freezeReactiveValue(rv) for. In
# the spirit of not breaking things we don't understand, we're making as
# targeted a fix as possible, while emitting a deprecation warning (below)
# that should help us gather more data about the other case.
impl$freeze(key, invalidate = is_input)
if (is_input) {
# Notify the client that this input was frozen. The client will ensure
# that the next time it sees a value for that input, even if the value
# has not changed from the last known value of that input, it will be
# sent to the server anyway.
private$sendMessage(frozen = list(
ids = list(key)
))
} else {
if (getOption("shiny.deprecation.messages", TRUE) && getOption("shiny.deprecation.messages.freeze", TRUE)) {
rlang::warn(
"Support for calling freezeReactiveValue() with non-`input` reactiveValues objects is soft-deprecated, and may be removed in a future version of Shiny. (See https://github.com/rstudio/shiny/issues/3063)",
.frequency = "once", .frequency_id = "freezeReactiveValue")
}
}
self$onFlushed(function() impl$thaw(key))
},
@@ -1238,6 +1279,41 @@ ShinySession <- R6Class(
modal = list(type = type, message = message)
)
},
setCurrentTheme = function(theme) {
# This function does three things: (1) sets theme as the current
# bootstrapTheme, (2) re-executes any registered theme dependencies, and
# (3) sends the resulting dependencies to the client.
# Note that this will automatically scope to the session.
shinyOptions(bootstrapTheme = theme)
# Call any theme dependency functions and make sure we get a list of deps back
funcs <- getShinyOption("themeDependencyFuncs")
deps <- lapply(funcs, function(func) {
deps <- func(theme)
if (length(deps) == 0) return(NULL)
if (inherits(deps, "html_dependency")) return(list(deps))
is_dep <- vapply(deps, inherits, logical(1), "html_dependency")
if (all(is_dep)) return(deps)
stop("All registerThemeDependency() functions must yield htmlDependency() object(s)", call. = FALSE)
})
# Work with a flat list of dependencies
deps <- unlist(dropNulls(deps), recursive = FALSE)
# Add a special flag to let Shiny.renderDependencies() know that, even
# though we've already rendered the dependency, that we need to re-render
# the stylesheets
deps <- lapply(deps, function(dep) {
dep$restyle <- TRUE
dep
})
# Send any dependencies to be re-rendered
if (length(deps)) {
insertUI(selector = "body", where = "afterEnd", ui = tagList(deps))
}
},
dispatch = function(msg) {
method <- paste('@', msg$method, sep='')
func <- try(self[[method]], silent = TRUE)
@@ -1671,10 +1747,6 @@ ShinySession <- R6Class(
)
},
# Public RPC methods
`@uploadieFinish` = function() {
# Do nothing; just want the side effect of flushReact, output flush, etc.
},
`@uploadInit` = function(fileInfos) {
maxSize <- getOption('shiny.maxRequestSize', 5 * 1024 * 1024)
fileInfos <- lapply(fileInfos, function(fi) {
@@ -1741,33 +1813,6 @@ ShinySession <- R6Class(
}
}
# @description Only applicable to files uploaded via IE. When possible,
# adds the appropriate extension to temporary files created by
# \code{mime::parse_multipart}.
# @param multipart A named list as returned by
# \code{mime::parse_multipart}
# @return A named list with datapath updated to point to the new location
# of the file, if an extension was added.
maybeMoveIEUpload <- function(multipart) {
if (is.null(multipart)) return(NULL)
lapply(multipart, function(input) {
oldPath <- input$datapath
newPath <- paste0(oldPath, maybeGetExtension(input$name))
if (oldPath != newPath) {
file.rename(oldPath, newPath)
input$datapath <- newPath
}
input
})
}
if (matches[2] == 'uploadie' && identical(req$REQUEST_METHOD, "POST")) {
id <- URLdecode(matches[3])
res <- maybeMoveIEUpload(mime::parse_multipart(req))
private$.input$set(id, res[[id]])
return(httpResponse(200, 'text/plain', 'OK'))
}
if (matches[2] == 'download') {
@@ -1876,33 +1921,18 @@ ShinySession <- R6Class(
return(httpResponse(404, 'text/html', '<h1>Not Found</h1>'))
},
saveFileUrl = function(name, data, contentType, extra=list()) {
"Creates an entry in the file map for the data, and returns a URL pointing
to the file."
self$files$set(name, list(data=data, contentType=contentType))
return(sprintf('session/%s/file/%s?w=%s&r=%s',
URLencode(self$token, TRUE),
URLencode(name, TRUE),
workerId(),
createUniqueId(8)))
},
# Send a file to the client
fileUrl = function(name, file, contentType='application/octet-stream') {
"Return a URL for a file to be sent to the client. If allowDataUriScheme
is TRUE, then the file will be base64 encoded and embedded in the URL.
Otherwise, a URL pointing to the file will be returned."
"Return a URL for a file to be sent to the client. The file will be base64
encoded and embedded in the URL."
bytes <- file.info(file)$size
if (is.na(bytes))
return(NULL)
fileData <- readBin(file, 'raw', n=bytes)
if (isTRUE(private$.clientData$.values$get("allowDataUriScheme"))) {
b64 <- rawToBase64(fileData)
return(paste('data:', contentType, ';base64,', b64, sep=''))
} else {
return(self$saveFileUrl(name, fileData, contentType))
}
b64 <- rawToBase64(fileData)
return(paste('data:', contentType, ';base64,', b64, sep=''))
},
registerDownload = function(name, filename, contentType, func) {

View File

@@ -93,8 +93,7 @@ shinyApp <- function(ui, server, onStart=NULL, options=list(),
# Store the appDir and bookmarking-related options, so that we can read them
# from within the app.
shinyOptions(appDir = getwd())
appOptions <- consumeAppOptions()
appOptions <- captureAppOptions()
structure(
list(
@@ -385,27 +384,30 @@ shinyAppDir_appR <- function(fileName, appDir, options=list())
{
fullpath <- file.path.ci(appDir, fileName)
# In an upcoming version of shiny, this option will go away.
if (getOption("shiny.autoload.r", TRUE)) {
# Create a child env which contains all the helpers and will be the shared parent
# of the ui.R and server.R load.
sharedEnv <- new.env(parent = globalenv())
} else {
sharedEnv <- globalenv()
}
# This sources app.R and caches the content. When appObj() is called but
# app.R hasn't changed, it won't re-source the file. But if called and
# app.R has changed, it'll re-source the file and return the result.
appObj <- cachedFuncWithFile(appDir, fileName, case.sensitive = FALSE,
function(appR) {
wasDir <- setwd(appDir)
on.exit(setwd(wasDir))
# TODO: we should support hot reloading on R/*.R changes.
# In an upcoming version of shiny, this option will go away.
if (getOption("shiny.autoload.r", TRUE)) {
# Create a child env which contains all the helpers and will be the shared parent
# of the ui.R and server.R load.
sharedEnv <- new.env(parent = globalenv())
loadSupport(appDir, renv=sharedEnv, globalrenv=NULL)
} else {
sharedEnv <- globalenv()
}
result <- sourceUTF8(fullpath, envir = new.env(parent = sharedEnv))
if (!is.shiny.appobj(result))
stop("app.R did not return a shiny.appobj object.")
unconsumeAppOptions(result$appOptions)
applyCapturedAppOptions(result$appOptions)
return(result)
}
@@ -443,10 +445,6 @@ shinyAppDir_appR <- function(fileName, appDir, options=list())
onStart <- function() {
oldwd <<- getwd()
setwd(appDir)
# TODO: we should support hot reloading on R/*.R changes.
if (getOption("shiny.autoload.r", TRUE)) {
loadSupport(appDir, renv=sharedEnv, globalrenv=NULL)
}
if (!is.null(appObj()$onStart)) appObj()$onStart()
monitorHandle <<- initAutoReloadMonitor(appDir)
invisible()
@@ -462,6 +460,8 @@ shinyAppDir_appR <- function(fileName, appDir, options=list())
}
}
appObjOptions <- appObj()$options
structure(
list(
# fallbackWWWDir is _not_ listed in staticPaths, because it needs to
@@ -480,7 +480,7 @@ shinyAppDir_appR <- function(fileName, appDir, options=list())
serverFuncSource = dynServerFuncSource,
onStart = onStart,
onStop = onStop,
options = options
options = joinOptions(appObjOptions, options)
),
class = "shiny.appobj"
)
@@ -530,18 +530,25 @@ is.shiny.appobj <- function(x) {
}
#' @rdname shiny.appobj
#' @param ... Additional parameters to be passed to print.
#' @param ... Ignored.
#' @export
print.shiny.appobj <- function(x, ...) {
opts <- x$options %OR% list()
opts <- opts[names(opts) %in%
c("port", "launch.browser", "host", "quiet",
"display.mode", "test.mode")]
runApp(x)
}
# Quote x and put runApp in quotes so that there's a nicer stack trace (#1851)
args <- c(list(quote(x)), opts)
# Joins two options objects (i.e. the `options` argument to shinyApp(),
# shinyAppDir(), etc.). The values in `b` should take precedence over the values
# in `a`. Given the current options available, it is safe to throw away any
# values in `a` that are provided in `b`. But in the future, if new options are
# introduced that need to be combined in some way instead of simply overwritten,
# then this will be the place to do it. See the implementations of
# print.shiny.appobj() and runApp() (for the latter, look specifically for
# "findVal()") to determine the set of possible options.
joinOptions <- function(a, b) {
stopifnot(is.null(a) || is.list(a))
stopifnot(is.null(b) || is.list(b))
do.call("runApp", args)
mergeVectors(a, b)
}
#' @rdname shiny.appobj
@@ -571,84 +578,3 @@ deferredIFrame <- function(path, width, 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
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.
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
knit_print.reactive <- function(x, ..., inline = FALSE) {
renderFunc <- if (inline) renderText else renderPrint
knitr::knit_print(renderFunc({
x()
}), inline = inline)
}

View File

@@ -24,7 +24,9 @@ withMathJax <- function(...) {
)
}
renderPage <- function(ui, connection, showcase=0, testMode=FALSE) {
renderPage <- function(ui, showcase=0, testMode=FALSE) {
lang <- getLang(ui)
# 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")) {
@@ -38,7 +40,10 @@ renderPage <- function(ui, connection, showcase=0, testMode=FALSE) {
# Put the body into the default template
ui <- htmlTemplate(
system.file("template", "default.html", package = "shiny"),
body = ui
lang = lang,
body = ui,
# this template is a complete HTML document
document_ = TRUE
)
}
@@ -61,23 +66,58 @@ renderPage <- function(ui, connection, showcase=0, testMode=FALSE) {
stop("Unsupported version of jQuery: ", version)
}
shiny_deps <- list(
htmlDependency("json2", "2014.02.04", c(href="shared"), script = "json2-min.js"),
jquery(),
htmlDependency("shiny", utils::packageVersion("shiny"), c(href="shared"),
script = if (getOption("shiny.minified", TRUE)) "shiny.min.js" else "shiny.js",
stylesheet = "shiny.css")
shiny_deps <- c(
list(jquery()),
shinyDependencies()
)
if (testMode) {
# Add code injection listener if in test mode
shiny_deps[[length(shiny_deps) + 1]] <-
htmlDependency("shiny-testmode", utils::packageVersion("shiny"),
c(href="shared"), script = "shiny-testmode.js")
c(href="shared"), script = "shiny-testmode.js")
}
html <- renderDocument(ui, shiny_deps, processDep = createWebDependency)
writeUTF8(html, con = connection)
enc2utf8(paste(collapse = "\n", html))
}
shinyDependencies <- function() {
version <- utils::packageVersion("shiny")
list(
bootstraplib::bs_dependency_defer(shinyDependencyCSS),
htmlDependency(
name = "shiny-javascript",
version = version,
src = c(href = "shared"),
script = if (getOption("shiny.minified", TRUE)) "shiny.min.js" else "shiny.js"
)
)
}
shinyDependencyCSS <- function(theme) {
version <- utils::packageVersion("shiny")
if (!is_bs_theme(theme)) {
return(htmlDependency(
name = "shiny-css",
version = version,
src = c(href = "shared"),
stylesheet = "shiny.min.css"
))
}
scss_home <- system.file("www/shared/shiny_scss", package = "shiny")
scss_files <- file.path(scss_home, c("bootstrap.scss", "shiny.scss"))
scss_files <- lapply(scss_files, sass::sass_file)
bootstraplib::bs_dependency(
input = scss_files,
theme = theme,
name = "shiny-sass",
version = version,
cache_key_extra = version
)
}
#' Create a Shiny UI handler
@@ -101,16 +141,18 @@ uiHttpHandler <- function(ui, uiPattern = "^/$") {
force(ui)
allowed_methods <- "GET"
if (is.function(ui)) {
allowed_methods <- attr(ui, "http_methods_supported", exact = TRUE) %OR% allowed_methods
}
function(req) {
if (!identical(req$REQUEST_METHOD, 'GET'))
if (!isTRUE(req$REQUEST_METHOD %in% allowed_methods))
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)
@@ -118,7 +160,7 @@ uiHttpHandler <- function(ui, uiPattern = "^/$") {
showcaseMode <- mode
}
testMode <- .globals$testMode %OR% FALSE
testMode <- getShinyOption("testmode", default = FALSE)
# Create a restore context using query string
bookmarkStore <- getShinyOption("bookmarkStore", default = "disable")
@@ -150,8 +192,11 @@ uiHttpHandler <- function(ui, uiPattern = "^/$") {
if (is.null(uiValue))
return(NULL)
renderPage(uiValue, textConn, showcaseMode, testMode)
html <- paste(readLines(textConn, encoding = 'UTF-8'), collapse='\n')
return(httpResponse(200, content=enc2utf8(html)))
if (inherits(uiValue, "httpResponse")) {
return(uiValue)
} else {
html <- renderPage(uiValue, showcaseMode, testMode)
return(httpResponse(200, content=html))
}
}
}

View File

@@ -372,35 +372,35 @@ isTemp <- function(path, tempDir = tempdir(), mustExist) {
return(substr(path, 1, nchar(tempDir)) == tempDir)
}
#' Printable Output
#' Text Output
#'
#' Makes a reactive version of the given function that captures any printed
#' output, and also captures its printable result (unless
#' [base::invisible()]), into a string. The resulting function is suitable
#' for assigning to an `output` slot.
#' @description
#' `renderPrint()` prints the result of `expr`, while `renderText()` pastes it
#' together into a single string. `renderPrint()` is equivalent to [print()];
#' `renderText()` is equivalent to [cat()]. Both functions capture all other
#' printed output generated while evaluating `expr`.
#'
#' `renderPrint()` is usually paired with [verbatimTextOutput()];
#' `renderText()` is usually paired with [textOutput()].
#'
#' @details
#' The corresponding HTML output tag can be anything (though `pre` is
#' recommended if you need a monospace font and whitespace preserved) and should
#' have the CSS class name `shiny-text-output`.
#'
#' The result of executing `func` will be printed inside a
#' [utils::capture.output()] call.
#' @return
#' For `renderPrint()`, note the given expression returns `NULL` then `NULL`
#' will actually be visible in the output. To display nothing, make your
#' function return [invisible()].
#'
#' Note that unlike most other Shiny output functions, if the given function
#' returns `NULL` then `NULL` will actually be visible in the output.
#' To display nothing, make your function return [base::invisible()].
#'
#' @param expr An expression that may print output and/or return a printable R
#' object.
#' @param env The environment in which to evaluate `expr`.
#' @param expr An expression to evaluate.
#' @param env The environment in which to evaluate `expr`. For expert use only.
#' @param quoted Is `expr` a quoted expression (with `quote()`)? This
#' is useful if you want to save an expression in a variable.
#' @param width The value for `[options][base::options]('width')`.
#' @param width Width of printed output.
#' @param outputArgs A list of arguments to be passed through to the implicit
#' call to [verbatimTextOutput()] when `renderPrint` is used
#' in an interactive R Markdown document.
#' @seealso [renderText()] for displaying the value returned from a
#' function, instead of the printed output.
#' call to [verbatimTextOutput()] or [textOutput()] when the functions are
#' used in an interactive RMarkdown document.
#'
#' @example res/text-example.R
#' @export
@@ -476,35 +476,10 @@ createRenderPrintPromiseDomain <- function(width) {
)
}
#' Text Output
#'
#' Makes a reactive version of the given function that also uses
#' [base::cat()] to turn its result into a single-element character
#' vector.
#'
#' The corresponding HTML output tag can be anything (though `pre` is
#' recommended if you need a monospace font and whitespace preserved) and should
#' have the CSS class name `shiny-text-output`.
#'
#' The result of executing `func` will passed to `cat`, inside a
#' [utils::capture.output()] call.
#'
#' @param expr An expression that returns an R object that can be used as an
#' argument to `cat`.
#' @param env The environment in which to evaluate `expr`.
#' @param quoted Is `expr` a quoted expression (with `quote()`)? This
#' is useful if you want to save an expression in a variable.
#' @param outputArgs A list of arguments to be passed through to the implicit
#' call to [textOutput()] when `renderText` is used in an
#' interactive R Markdown document.
#' @param sep A separator passed to `cat` to be appended after each
#' element.
#'
#' @seealso [renderPrint()] for capturing the print output of a
#' function, rather than the returned text value.
#'
#' @example res/text-example.R
#' @export
#' @rdname renderPrint
renderText <- function(expr, env=parent.frame(), quoted=FALSE,
outputArgs=list(), sep=" ") {
installExprFunction(expr, "func", env, quoted)

View File

@@ -220,4 +220,3 @@ showcaseUI <- function(ui) {
showcaseBody(ui)
)
}

View File

@@ -1,23 +1,20 @@
#' @noRd
isModuleServer <- function(x) {
is.function(x) && names(formals(x))[1] == "id"
}
#' Reactive testing for Shiny server functions and modules
#'
#' A way to test the reactive interactions in Shiny applications. Reactive
#' interactions are defined in the server function of applications and in
#' modules.
#' @param app The path to an application or module to test. In addition to
#' paths, applications may be represented by any object suitable for coercion
#' to an `appObj` by [`as.shiny.appobj`]. Application server functions must
#' include a `session` argument in order to be tested. If `app` is `NULL` or
#' not supplied, the nearest enclosing directory that is a Shiny app, starting
#' with the current directory, is used.
#' @param expr Test code containing expectations. The test expression will run
#' in the server function environment, meaning that the parameters of the
#' server function (e.g. `input`, `output`, and `session`) will be available
#' along with any other values created inside of the server function.
#' @param app A server function (i.e. a function with `input`, `output`,
#' and `session`), or a module function (i.e. a function with first
#' argument `id` that calls [moduleServer()].
#'
#' You can also provide an app, a path an app, or anything that
#' [`as.shiny.appobj()`] can handle.
#' @param expr Test code containing expectations. The objects from inside the
#' server function environment will be made available in the environment of
#' the test expression (this is done using a data mask with
#' [rlang::eval_tidy()]). This includes the parameters of the server function
#' (e.g. `input`, `output`, and `session`), along with any other values
#' created inside of the server function.
#' @param args Additional arguments to pass to the module function. If `app` is
#' a module, and no `id` argument is provided, one will be generated and
#' supplied automatically.
@@ -28,7 +25,19 @@ isModuleServer <- function(x) {
#' @include mock-session.R
#' @rdname testServer
#' @examples
#' server <- function(id, multiplier = 2, prefix = "I am ") {
#' # Testing a server function ----------------------------------------------
#' server <- function(input, output, session) {
#' x <- reactive(input$a * input$b)
#' }
#'
#' testServer(server, {
#' session$setInputs(a = 2, b = 3)
#' stopifnot(x() == 6)
#' })
#'
#'
#' # Testing a module --------------------------------------------------------
#' myModuleServer <- function(id, multiplier = 2, prefix = "I am ") {
#' moduleServer(id, function(input, output, session) {
#' myreactive <- reactive({
#' input$x * multiplier
@@ -39,7 +48,7 @@ isModuleServer <- function(x) {
#' })
#' }
#'
#' testServer(server, args = list(multiplier = 2), {
#' testServer(myModuleServer, args = list(multiplier = 2), {
#' session$setInputs(x = 1)
#' # You're also free to use third-party
#' # testing packages like testthat:
@@ -54,74 +63,94 @@ isModuleServer <- function(x) {
#' })
#' @export
testServer <- function(app = NULL, expr, args = list(), session = MockShinySession$new()) {
require(shiny)
if (!is.null(getDefaultReactiveDomain()))
stop("testServer() is for use only within tests and may not indirectly call itself.")
on.exit(if (!session$isClosed()) session$close(), add = TRUE)
quosure <- rlang::enquo(expr)
on.exit(if (!session$isClosed()) session$close())
withMockContext <- function(expr) {
isolate(
withReactiveDomain(session, {
withr::with_options(list(`shiny.allowoutputreads` = TRUE), {
withLocalOptions({
# Sets a cache for renderCachedPlot() with cache = "app" to use.
shinyOptions("cache" = session$appcache)
expr
})
})
})
)
}
if (isModuleServer(app)) {
if (!("id" %in% names(args)))
args[["id"]] <- session$genId()
# app is presumed to be a module, and modules may take additional arguments,
# so splice in any args.
withMockContext(rlang::exec(app, !!!args))
withMockContext(session, rlang::exec(app, !!!args))
# If app is a module, then we must use both the module function's immediate
# environment and also its enclosing environment to construct the mask.
parent_clone <- rlang::env_clone(parent.env(session$env))
clone <- rlang::env_clone(session$env, parent_clone)
mask <- rlang::new_data_mask(clone, parent_clone)
withMockContext(rlang::eval_tidy(quosure, mask, rlang::caller_env()))
} else {
if (is.null(app)) {
app <- findEnclosingApp(".")
}
appobj <- as.shiny.appobj(app)
if (!is.null(appobj$onStart))
appobj$onStart()
# Ensure appobj$onStop() is called, and the current directory is restored,
# regardless of whether invoking the server function is successful.
tryCatch({
server <- appobj$serverFuncSource()
if (! "session" %in% names(formals(server)))
stop("Tested application server functions must declare input, output, and session arguments.")
body(server) <- rlang::expr({
session$setEnv(base::environment())
!!body(server)
})
if (length(args))
stop("Arguments were provided to a server function.")
withMockContext(server(input = session$input, output = session$output, session = session))
}, finally = {
if (!is.null(appobj$onStop))
appobj$onStop()
})
# If app is a server, we use only the server function's immediate
# environment to construct the mask.
mask <- rlang::new_data_mask(rlang::env_clone(session$env))
withMockContext(rlang::eval_tidy(quosure, mask, rlang::caller_env()))
withMockContext(session, rlang::eval_tidy(quosure, mask, rlang::caller_env()))
return(invisible())
}
if (is.null(app)) {
path <- findEnclosingApp(".")
app <- shinyAppDir(path)
} else if (isServer(app)) {
app <- shinyApp(fluidPage(), app)
} else {
app <- as.shiny.appobj(app)
}
if (!is.null(app$onStart))
app$onStart()
if (!is.null(app$onStop))
on.exit(app$onStop(), add = TRUE)
server <- app$serverFuncSource()
if (!"session" %in% names(formals(server)))
stop("Tested application server functions must declare input, output, and session arguments.")
if (length(args))
stop("Arguments were provided to a server function.")
body(server) <- rlang::expr({
session$setEnv(base::environment())
!!body(server)
})
withMockContext(session,
server(input = session$input, output = session$output, session = session)
)
# # If app is a server, we use only the server function's immediate
# # environment to construct the mask.
mask <- rlang::new_data_mask(rlang::env_clone(session$env))
withMockContext(session, {
rlang::eval_tidy(quosure, mask, rlang::caller_env())
})
invisible()
}
withMockContext <- function(session, expr) {
isolate(
withReactiveDomain(session, {
withr::with_options(list(`shiny.allowoutputreads` = TRUE), {
# Sets a cache for renderCachedPlot() with cache = "app" to use.
shinyOptions("cache" = session$appcache)
expr
})
})
)
}
# Helpers -----------------------------------------------------------------
isModuleServer <- function(x) {
is.function(x) && names(formals(x))[[1]] == "id"
}
isServer <- function(x) {
if (!is.function(x)) {
return(FALSE)
}
if (length(formals(x)) < 3) {
return(FALSE)
}
identical(names(formals(x))[1:3], c("input", "output", "session"))
}

View File

@@ -1,8 +1,7 @@
#' Change the value of a text input on the client
#'
#' @template update-input
#' @param value The value to set for the input object.
#' @param placeholder The placeholder to set for the input object.
#' @inheritParams textInput
#'
#' @seealso [textInput()]
#'
@@ -82,7 +81,7 @@ updateTextAreaInput <- updateTextInput
#' Change the value of a checkbox input on the client
#'
#' @template update-input
#' @param value The value to set for the input object.
#' @inheritParams checkboxInput
#'
#' @seealso [checkboxInput()]
#'
@@ -116,8 +115,7 @@ updateCheckboxInput <- function(session, inputId, label = NULL, value = NULL) {
#' Change the label or icon of an action button on the client
#'
#' @template update-input
#' @param icon The icon to set for the input object. To remove the
#' current icon, use `icon=character(0)`.
#' @inheritParams actionButton
#'
#' @seealso [actionButton()]
#'
@@ -180,12 +178,7 @@ updateActionLink <- updateActionButton
#' Change the value of a date input on the client
#'
#' @template update-input
#' @param value The desired date value. Either a Date object, or a string in
#' `yyyy-mm-dd` format. Supply `NA` to clear the date.
#' @param min The minimum allowed date. Either a Date object, or a string in
#' `yyyy-mm-dd` format.
#' @param max The maximum allowed date. Either a Date object, or a string in
#' `yyyy-mm-dd` format.
#' @inheritParams dateInput
#'
#' @seealso [dateInput()]
#'
@@ -228,14 +221,7 @@ updateDateInput <- function(session, inputId, label = NULL, value = NULL,
#' Change the start and end values of a date range input on the client
#'
#' @template update-input
#' @param start The start date. Either a Date object, or a string in
#' `yyyy-mm-dd` format. Supplying `NA` clears the start date.
#' @param end The end date. Either a Date object, or a string in
#' `yyyy-mm-dd` format. Supplying `NA` clears the end date.
#' @param min The minimum allowed date. Either a Date object, or a string in
#' `yyyy-mm-dd` format.
#' @param max The maximum allowed date. Either a Date object, or a string in
#' `yyyy-mm-dd` format.
#' @inheritParams dateRangeInput
#'
#' @seealso [dateRangeInput()]
#'
@@ -290,7 +276,7 @@ updateDateRangeInput <- function(session, inputId, label = NULL,
#' `shinyServer`.
#' @param inputId The id of the `tabsetPanel`, `navlistPanel`,
#' or `navbarPage` object.
#' @param selected The name of the tab to make active.
#' @inheritParams tabsetPanel
#'
#' @seealso [tabsetPanel()], [navlistPanel()],
#' [navbarPage()]
@@ -339,10 +325,7 @@ updateNavlistPanel <- updateTabsetPanel
#' Change the value of a number 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.
#' @inheritParams numericInput
#'
#' @seealso [numericInput()]
#'
@@ -389,12 +372,7 @@ updateNumericInput <- function(session, inputId, label = NULL, value = NULL,
#' 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.
#' @param timeFormat Date and POSIXt formatting.
#' @param timezone The timezone offset for POSIXt objects.
#' @inheritParams sliderInput
#'
#' @seealso [sliderInput()]
#'
@@ -617,7 +595,7 @@ updateSelectInput <- function(session, inputId, label = NULL, choices = NULL,
selected = NULL) {
choices <- if (!is.null(choices)) choicesWithNames(choices)
if (!is.null(selected)) selected <- as.character(selected)
options <- if (!is.null(choices)) selectOptions(choices, selected)
options <- if (!is.null(choices)) selectOptions(choices, selected, inputId, FALSE)
message <- dropNulls(list(label = label, options = options, value = selected))
session$sendInputMessage(inputId, message)
}

View File

@@ -1594,7 +1594,6 @@ URLencode <- function(value, reserved = FALSE) {
# so that strings like "2016-08-9" are expanded to "2016-08-09"
dateYMD <- function(date = NULL, argName = "value") {
if (!length(date)) return(NULL)
if (length(date) > 1) warning("Expected `", argName, "` to be of length 1.")
tryCatch(date <- format(as.Date(date), "%Y-%m-%d"),
error = function(e) {
warning(

56
R/viewer.R Normal file
View File

@@ -0,0 +1,56 @@
#' 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
#' [utils::browseURL()]).
#'
#' @return A function that takes a single `url` parameter, suitable for
#' passing as the `viewer` argument of [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 `NULL`, use the existing viewer pane
#' size. If `"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 [utils::browseURL()].
#' @rdname viewer
#' @export
browserViewer <- function(browser = getOption("browser")) {
function(url) {
utils::browseURL(url, browser = browser)
}
}

View File

@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html{{ if (isTRUE(nzchar(lang))) paste0(" lang=\"", lang, "\"") }}>
<head>
{{ headContent() }}
</head>

View File

@@ -1,6 +1,6 @@
<html>
<head>
<head lang = "en">
<title>An error has occurred</title>
</head>

View File

@@ -0,0 +1 @@
.btn:focus{outline:dotted 2px #000}div.active:focus{outline:dotted 1px #000}a:focus{outline:dotted 1px #000}.close:hover,.close:focus{outline:dotted 1px #000}.nav>li>a:hover,.nav>li>a:focus{outline:dotted 1px #000}.carousel-indicators li,.carousel-indicators li.active{height:18px;width:18px;border-width:2px;position:relative;box-shadow:0px 0px 0px 1px #808080}.carousel-indicators.active li{background-color:rgba(100,149,253,0.6)}.carousel-indicators.active li.active{background-color:white}.carousel-tablist-highlight{display:block;position:absolute;outline:2px solid transparent;background-color:transparent;box-shadow:0px 0px 0px 1px transparent}.carousel-tablist-highlight.focus{outline:2px solid #6495ED;background-color:rgba(0,0,0,0.4)}a.carousel-control:focus{outline:2px solid #6495ED;background-image:linear-gradient(to right, transparent 0px, rgba(0,0,0,0.5) 100%);box-shadow:0px 0px 0px 1px #000000}.carousel-pause-button{position:absolute;top:-30em;left:-300em;display:block}.carousel-pause-button.focus{top:0.5em;left:0.5em}.carousel:hover .carousel-caption,.carousel.contrast .carousel-caption{background-color:rgba(0,0,0,0.5);z-index:10}.alert-success{color:#2d4821}.alert-info{color:#214c62}.alert-warning{color:#6c4a00;background-color:#f9f1c6}.alert-danger{color:#d2322d}.alert-danger:hover{color:#a82824}

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +0,0 @@
/**
* @preserve HTML5 Shiv 3.7.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
*/
// Only run this code in IE 8
if (!!window.navigator.userAgent.match("MSIE 8")) {
!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.2",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b)}(this,document);
};

View File

@@ -1,8 +0,0 @@
/*! Respond.js v1.4.2: min/max-width media query polyfill * Copyright 2013 Scott Jehl
* Licensed under https://github.com/scottjehl/Respond/blob/master/LICENSE-MIT
* */
// Only run this code in IE 8
if (!!window.navigator.userAgent.match("MSIE 8")) {
!function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='&shy;<style media="'+a+'"> #mq-test-1 { width: 42px; }</style>',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){u(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))};if(c.ajax=f,c.queue=d,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,maxw:/\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var g,h,i,j=a.document,k=j.documentElement,l=[],m=[],n=[],o={},p=30,q=j.getElementsByTagName("head")[0]||k,r=j.getElementsByTagName("base")[0],s=q.getElementsByTagName("link"),t=function(){var a,b=j.createElement("div"),c=j.body,d=k.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=j.createElement("body"),c.style.background="none"),k.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&k.insertBefore(c,k.firstChild),a=b.offsetWidth,f?k.removeChild(c):c.removeChild(b),k.style.fontSize=d,e&&(c.style.fontSize=e),a=i=parseFloat(a)},u=function(b){var c="clientWidth",d=k[c],e="CSS1Compat"===j.compatMode&&d||j.body[c]||d,f={},o=s[s.length-1],r=(new Date).getTime();if(b&&g&&p>r-g)return a.clearTimeout(h),h=a.setTimeout(u,p),void 0;g=r;for(var v in l)if(l.hasOwnProperty(v)){var w=l[v],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?i||t():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?i||t():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(m[w.rules]))}for(var C in n)n.hasOwnProperty(C)&&n[C]&&n[C].parentNode===q&&q.removeChild(n[C]);n.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=j.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,q.insertBefore(E,o.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(j.createTextNode(F)),n.push(E)}},v=function(a,b,d){var e=a.replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var g=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},h=!f&&d;b.length&&(b+="/"),h&&(f=1);for(var i=0;f>i;i++){var j,k,n,o;h?(j=d,m.push(g(a))):(j=e[i].match(c.regex.findStyles)&&RegExp.$1,m.push(RegExp.$2&&g(RegExp.$2))),n=j.split(","),o=n.length;for(var p=0;o>p;p++)k=n[p],l.push({media:k.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:m.length-1,hasquery:k.indexOf("(")>-1,minw:k.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:k.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},w=function(){if(d.length){var b=d.shift();f(b.href,function(c){v(c,b.href,b.media),o[b.href]=!0,a.setTimeout(function(){w()},0)})}},x=function(){for(var b=0;b<s.length;b++){var c=s[b],e=c.href,f=c.media,g=c.rel&&"stylesheet"===c.rel.toLowerCase();e&&g&&!o[e]&&(c.styleSheet&&c.styleSheet.rawCssText?(v(c.styleSheet.rawCssText,e,f),o[e]=!0):(!/^([a-zA-Z:]*\/\/)/.test(e)&&!r||e.replace(RegExp.$1,"").split("/")[0]===a.location.host)&&("//"===e.substring(0,2)&&(e=a.location.protocol+e),d.push({href:e,media:f})))}w()};x(),c.update=x,c.getEmValue=t,a.addEventListener?a.addEventListener("resize",b,!1):a.attachEvent&&a.attachEvent("onresize",b)}}(this);
};

View File

@@ -1,28 +1,30 @@
/*!
* Datepicker for Bootstrap v1.6.4 (https://github.com/eternicode/bootstrap-datepicker)
*
* Copyright 2012 Stefan Petre
* Improvements by Andrew Rowls
* Licensed under the Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/
.datepicker {
border-radius: 4px;
border-radius: 0.25rem;
direction: ltr;
}
.datepicker-inline {
width: 220px;
}
.datepicker.datepicker-rtl {
.datepicker-rtl {
direction: rtl;
}
.datepicker.datepicker-rtl table tr td span {
.datepicker-rtl.dropdown-menu {
left: auto;
}
.datepicker-rtl table tr td span {
float: right;
}
.datepicker-dropdown {
top: 0;
left: 0;
padding: 4px;
}
.datepicker-dropdown:before {
content: '';
display: inline-block;
@@ -33,6 +35,7 @@
border-bottom-color: rgba(0, 0, 0, 0.2);
position: absolute;
}
.datepicker-dropdown:after {
content: '';
display: inline-block;
@@ -42,34 +45,43 @@
border-top: 0;
position: absolute;
}
.datepicker-dropdown.datepicker-orient-left:before {
left: 6px;
}
.datepicker-dropdown.datepicker-orient-left:after {
left: 7px;
}
.datepicker-dropdown.datepicker-orient-right:before {
right: 6px;
}
.datepicker-dropdown.datepicker-orient-right:after {
right: 7px;
}
.datepicker-dropdown.datepicker-orient-bottom:before {
top: -7px;
}
.datepicker-dropdown.datepicker-orient-bottom:after {
top: -6px;
}
.datepicker-dropdown.datepicker-orient-top:before {
bottom: -7px;
border-bottom: 0;
border-top: 7px solid rgba(0, 0, 0, 0.15);
}
.datepicker-dropdown.datepicker-orient-top:after {
bottom: -6px;
border-bottom: 0;
border-top: 6px solid #fff;
}
.datepicker table {
margin: 0;
-webkit-touch-callout: none;
@@ -79,424 +91,352 @@
-ms-user-select: none;
user-select: none;
}
.datepicker table tr td,
.datepicker table tr th {
.datepicker table tr td, .datepicker table tr th {
text-align: center;
width: 30px;
height: 30px;
border-radius: 4px;
border: none;
}
.table-striped .datepicker table tr td,
.table-striped .datepicker table tr th {
.table-striped .datepicker table tr td, .table-striped .datepicker table tr th {
background-color: transparent;
}
.datepicker table tr td.old,
.datepicker table tr td.new {
color: #777777;
.datepicker table tr td.old, .datepicker table tr td.new {
color: #6c757d;
}
.datepicker table tr td.day:hover,
.datepicker table tr td.focused {
background: #eeeeee;
.datepicker table tr td.day:hover, .datepicker table tr td.focused {
color: #212529;
background: #e9e9ea;
cursor: pointer;
}
.datepicker table tr td.disabled,
.datepicker table tr td.disabled:hover {
.datepicker table tr td.disabled, .datepicker table tr td.disabled:hover {
background: none;
color: #777777;
color: #6c757d;
cursor: default;
}
.datepicker table tr td.highlighted {
color: #000;
background-color: #d9edf7;
border-color: #85c5e5;
color: #212529;
background-color: #d1ecf1;
border-color: #83ccd9;
border-radius: 0;
}
.datepicker table tr td.highlighted:focus,
.datepicker table tr td.highlighted.focus {
color: #000;
background-color: #afd9ee;
border-color: #298fc2;
.datepicker table tr td.highlighted:focus, .datepicker table tr td.highlighted.focus {
color: #212529;
background-color: #bfd8dd;
border-color: #6aa2ad;
}
.datepicker table tr td.highlighted:hover {
color: #000;
background-color: #afd9ee;
border-color: #52addb;
color: #212529;
background-color: #79898d;
border-color: #77b8c4;
}
.datepicker table tr td.highlighted:active,
.datepicker table tr td.highlighted.active {
color: #000;
background-color: #afd9ee;
border-color: #52addb;
.datepicker table tr td.highlighted:active, .datepicker table tr td.highlighted.active {
color: #212529;
background-color: #bfd8dd;
border-color: #77b8c4;
}
.datepicker table tr td.highlighted:active:hover,
.datepicker table tr td.highlighted.active:hover,
.datepicker table tr td.highlighted:active:focus,
.datepicker table tr td.highlighted.active:focus,
.datepicker table tr td.highlighted:active.focus,
.datepicker table tr td.highlighted.active.focus {
color: #000;
background-color: #91cbe8;
border-color: #298fc2;
.datepicker table tr td.highlighted:active:hover, .datepicker table tr td.highlighted:active:focus, .datepicker table tr td.highlighted:active.focus, .datepicker table tr td.highlighted.active:hover, .datepicker table tr td.highlighted.active:focus, .datepicker table tr td.highlighted.active.focus {
color: #212529;
background-color: #b3cacf;
border-color: #6aa2ad;
}
.datepicker table tr td.highlighted.disabled:hover,
.datepicker table tr td.highlighted[disabled]:hover,
.datepicker table tr td.highlighted.disabled:hover, .datepicker table tr td.highlighted.disabled:focus, .datepicker table tr td.highlighted.disabled.focus, .datepicker table tr td.highlighted[disabled]:hover, .datepicker table tr td.highlighted[disabled]:focus, .datepicker table tr td.highlighted[disabled].focus,
fieldset[disabled] .datepicker table tr td.highlighted:hover,
.datepicker table tr td.highlighted.disabled:focus,
.datepicker table tr td.highlighted[disabled]:focus,
fieldset[disabled] .datepicker table tr td.highlighted:focus,
.datepicker table tr td.highlighted.disabled.focus,
.datepicker table tr td.highlighted[disabled].focus,
fieldset[disabled] .datepicker table tr td.highlighted.focus {
background-color: #d9edf7;
border-color: #85c5e5;
background-color: #d1ecf1;
border-color: #83ccd9;
}
.datepicker table tr td.highlighted.focused {
background: #afd9ee;
background: #aadce5;
}
.datepicker table tr td.highlighted.disabled,
.datepicker table tr td.highlighted.disabled:active {
background: #d9edf7;
color: #777777;
.datepicker table tr td.highlighted.disabled, .datepicker table tr td.highlighted.disabled:active {
background: #d1ecf1;
color: #6c757d;
}
.datepicker table tr td.today {
color: #000;
color: #212529;
background-color: #ffdb99;
border-color: #ffb733;
}
.datepicker table tr td.today:focus,
.datepicker table tr td.today.focus {
color: #000;
background-color: #ffc966;
border-color: #b37400;
.datepicker table tr td.today:focus, .datepicker table tr td.today.focus {
color: #212529;
background-color: #e9c98e;
border-color: #c89331;
}
.datepicker table tr td.today:hover {
color: #000;
background-color: #ffc966;
border-color: #f59e00;
color: #212529;
background-color: #908061;
border-color: #e4a532;
}
.datepicker table tr td.today:active,
.datepicker table tr td.today.active {
color: #000;
background-color: #ffc966;
border-color: #f59e00;
.datepicker table tr td.today:active, .datepicker table tr td.today.active {
color: #212529;
background-color: #e9c98e;
border-color: #e4a532;
}
.datepicker table tr td.today:active:hover,
.datepicker table tr td.today.active:hover,
.datepicker table tr td.today:active:focus,
.datepicker table tr td.today.active:focus,
.datepicker table tr td.today:active.focus,
.datepicker table tr td.today.active.focus {
color: #000;
background-color: #ffbc42;
border-color: #b37400;
.datepicker table tr td.today:active:hover, .datepicker table tr td.today:active:focus, .datepicker table tr td.today:active.focus, .datepicker table tr td.today.active:hover, .datepicker table tr td.today.active:focus, .datepicker table tr td.today.active.focus {
color: #212529;
background-color: #d9bc86;
border-color: #c89331;
}
.datepicker table tr td.today.disabled:hover,
.datepicker table tr td.today[disabled]:hover,
.datepicker table tr td.today.disabled:hover, .datepicker table tr td.today.disabled:focus, .datepicker table tr td.today.disabled.focus, .datepicker table tr td.today[disabled]:hover, .datepicker table tr td.today[disabled]:focus, .datepicker table tr td.today[disabled].focus,
fieldset[disabled] .datepicker table tr td.today:hover,
.datepicker table tr td.today.disabled:focus,
.datepicker table tr td.today[disabled]:focus,
fieldset[disabled] .datepicker table tr td.today:focus,
.datepicker table tr td.today.disabled.focus,
.datepicker table tr td.today[disabled].focus,
fieldset[disabled] .datepicker table tr td.today.focus {
background-color: #ffdb99;
border-color: #ffb733;
}
.datepicker table tr td.today.focused {
background: #ffc966;
}
.datepicker table tr td.today.disabled,
.datepicker table tr td.today.disabled:active {
.datepicker table tr td.today.disabled, .datepicker table tr td.today.disabled:active {
background: #ffdb99;
color: #777777;
color: #6c757d;
}
.datepicker table tr td.range {
color: #000;
background-color: #eeeeee;
border-color: #bbbbbb;
color: #212529;
background-color: #e9e9ea;
border-color: #b5b5b8;
border-radius: 0;
}
.datepicker table tr td.range:focus,
.datepicker table tr td.range.focus {
color: #000;
background-color: #d5d5d5;
border-color: #7c7c7c;
.datepicker table tr td.range:focus, .datepicker table tr td.range.focus {
color: #212529;
background-color: #d5d5d7;
border-color: #909194;
}
.datepicker table tr td.range:hover {
color: #000;
background-color: #d5d5d5;
border-color: #9d9d9d;
color: #212529;
background-color: #85878a;
border-color: #a3a4a7;
}
.datepicker table tr td.range:active,
.datepicker table tr td.range.active {
color: #000;
background-color: #d5d5d5;
border-color: #9d9d9d;
.datepicker table tr td.range:active, .datepicker table tr td.range.active {
color: #212529;
background-color: #d5d5d7;
border-color: #a3a4a7;
}
.datepicker table tr td.range:active:hover,
.datepicker table tr td.range.active:hover,
.datepicker table tr td.range:active:focus,
.datepicker table tr td.range.active:focus,
.datepicker table tr td.range:active.focus,
.datepicker table tr td.range.active.focus {
color: #000;
background-color: #c3c3c3;
border-color: #7c7c7c;
.datepicker table tr td.range:active:hover, .datepicker table tr td.range:active:focus, .datepicker table tr td.range:active.focus, .datepicker table tr td.range.active:hover, .datepicker table tr td.range.active:focus, .datepicker table tr td.range.active.focus {
color: #212529;
background-color: #c7c8c9;
border-color: #909194;
}
.datepicker table tr td.range.disabled:hover,
.datepicker table tr td.range[disabled]:hover,
.datepicker table tr td.range.disabled:hover, .datepicker table tr td.range.disabled:focus, .datepicker table tr td.range.disabled.focus, .datepicker table tr td.range[disabled]:hover, .datepicker table tr td.range[disabled]:focus, .datepicker table tr td.range[disabled].focus,
fieldset[disabled] .datepicker table tr td.range:hover,
.datepicker table tr td.range.disabled:focus,
.datepicker table tr td.range[disabled]:focus,
fieldset[disabled] .datepicker table tr td.range:focus,
.datepicker table tr td.range.disabled.focus,
.datepicker table tr td.range[disabled].focus,
fieldset[disabled] .datepicker table tr td.range.focus {
background-color: #eeeeee;
border-color: #bbbbbb;
background-color: #e9e9ea;
border-color: #b5b5b8;
}
.datepicker table tr td.range.focused {
background: #d5d5d5;
background: #cfcfd1;
}
.datepicker table tr td.range.disabled,
.datepicker table tr td.range.disabled:active {
background: #eeeeee;
color: #777777;
.datepicker table tr td.range.disabled, .datepicker table tr td.range.disabled:active {
background: #e9e9ea;
color: #6c757d;
}
.datepicker table tr td.range.highlighted {
color: #000;
background-color: #e4eef3;
border-color: #9dc1d3;
color: #212529;
background-color: #ddebee;
border-color: #99c3cc;
}
.datepicker table tr td.range.highlighted:focus,
.datepicker table tr td.range.highlighted.focus {
color: #000;
background-color: #c1d7e3;
border-color: #4b88a6;
.datepicker table tr td.range.highlighted:focus, .datepicker table tr td.range.highlighted.focus {
color: #212529;
background-color: #cad7da;
border-color: #7b9ca3;
}
.datepicker table tr td.range.highlighted:hover {
color: #000;
background-color: #c1d7e3;
border-color: #73a6c0;
color: #212529;
background-color: #7f888c;
border-color: #8bb0b8;
}
.datepicker table tr td.range.highlighted:active,
.datepicker table tr td.range.highlighted.active {
color: #000;
background-color: #c1d7e3;
border-color: #73a6c0;
.datepicker table tr td.range.highlighted:active, .datepicker table tr td.range.highlighted.active {
color: #212529;
background-color: #cad7da;
border-color: #8bb0b8;
}
.datepicker table tr td.range.highlighted:active:hover,
.datepicker table tr td.range.highlighted.active:hover,
.datepicker table tr td.range.highlighted:active:focus,
.datepicker table tr td.range.highlighted.active:focus,
.datepicker table tr td.range.highlighted:active.focus,
.datepicker table tr td.range.highlighted.active.focus {
color: #000;
background-color: #a8c8d8;
border-color: #4b88a6;
.datepicker table tr td.range.highlighted:active:hover, .datepicker table tr td.range.highlighted:active:focus, .datepicker table tr td.range.highlighted:active.focus, .datepicker table tr td.range.highlighted.active:hover, .datepicker table tr td.range.highlighted.active:focus, .datepicker table tr td.range.highlighted.active.focus {
color: #212529;
background-color: #bdc9cd;
border-color: #7b9ca3;
}
.datepicker table tr td.range.highlighted.disabled:hover,
.datepicker table tr td.range.highlighted[disabled]:hover,
.datepicker table tr td.range.highlighted.disabled:hover, .datepicker table tr td.range.highlighted.disabled:focus, .datepicker table tr td.range.highlighted.disabled.focus, .datepicker table tr td.range.highlighted[disabled]:hover, .datepicker table tr td.range.highlighted[disabled]:focus, .datepicker table tr td.range.highlighted[disabled].focus,
fieldset[disabled] .datepicker table tr td.range.highlighted:hover,
.datepicker table tr td.range.highlighted.disabled:focus,
.datepicker table tr td.range.highlighted[disabled]:focus,
fieldset[disabled] .datepicker table tr td.range.highlighted:focus,
.datepicker table tr td.range.highlighted.disabled.focus,
.datepicker table tr td.range.highlighted[disabled].focus,
fieldset[disabled] .datepicker table tr td.range.highlighted.focus {
background-color: #e4eef3;
border-color: #9dc1d3;
background-color: #ddebee;
border-color: #99c3cc;
}
.datepicker table tr td.range.highlighted.focused {
background: #c1d7e3;
background: #bbd7dd;
}
.datepicker table tr td.range.highlighted.disabled,
.datepicker table tr td.range.highlighted.disabled:active {
background: #e4eef3;
color: #777777;
.datepicker table tr td.range.highlighted.disabled, .datepicker table tr td.range.highlighted.disabled:active {
background: #ddebee;
color: #6c757d;
}
.datepicker table tr td.range.today {
color: #000;
background-color: #f7ca77;
border-color: #f1a417;
color: #212529;
background-color: #f4c775;
border-color: #eca117;
}
.datepicker table tr td.range.today:focus,
.datepicker table tr td.range.today.focus {
color: #000;
background-color: #f4b747;
border-color: #815608;
.datepicker table tr td.range.today:focus, .datepicker table tr td.range.today.focus {
color: #212529;
background-color: #dfb76d;
border-color: #ba821b;
}
.datepicker table tr td.range.today:hover {
color: #000;
background-color: #f4b747;
border-color: #bf800c;
color: #212529;
background-color: #8b764f;
border-color: #d49219;
}
.datepicker table tr td.range.today:active,
.datepicker table tr td.range.today.active {
color: #000;
background-color: #f4b747;
border-color: #bf800c;
.datepicker table tr td.range.today:active, .datepicker table tr td.range.today.active {
color: #212529;
background-color: #dfb76d;
border-color: #d49219;
}
.datepicker table tr td.range.today:active:hover,
.datepicker table tr td.range.today.active:hover,
.datepicker table tr td.range.today:active:focus,
.datepicker table tr td.range.today.active:focus,
.datepicker table tr td.range.today:active.focus,
.datepicker table tr td.range.today.active.focus {
color: #000;
background-color: #f2aa25;
border-color: #815608;
.datepicker table tr td.range.today:active:hover, .datepicker table tr td.range.today:active:focus, .datepicker table tr td.range.today:active.focus, .datepicker table tr td.range.today.active:hover, .datepicker table tr td.range.today.active:focus, .datepicker table tr td.range.today.active.focus {
color: #212529;
background-color: #d0ab68;
border-color: #ba821b;
}
.datepicker table tr td.range.today.disabled:hover,
.datepicker table tr td.range.today[disabled]:hover,
.datepicker table tr td.range.today.disabled:hover, .datepicker table tr td.range.today.disabled:focus, .datepicker table tr td.range.today.disabled.focus, .datepicker table tr td.range.today[disabled]:hover, .datepicker table tr td.range.today[disabled]:focus, .datepicker table tr td.range.today[disabled].focus,
fieldset[disabled] .datepicker table tr td.range.today:hover,
.datepicker table tr td.range.today.disabled:focus,
.datepicker table tr td.range.today[disabled]:focus,
fieldset[disabled] .datepicker table tr td.range.today:focus,
.datepicker table tr td.range.today.disabled.focus,
.datepicker table tr td.range.today[disabled].focus,
fieldset[disabled] .datepicker table tr td.range.today.focus {
background-color: #f7ca77;
border-color: #f1a417;
background-color: #f4c775;
border-color: #eca117;
}
.datepicker table tr td.range.today.disabled,
.datepicker table tr td.range.today.disabled:active {
background: #f7ca77;
color: #777777;
.datepicker table tr td.range.today.disabled, .datepicker table tr td.range.today.disabled:active {
background: #f4c775;
color: #6c757d;
}
.datepicker table tr td.selected,
.datepicker table tr td.selected.highlighted {
.datepicker table tr td.selected, .datepicker table tr td.selected.highlighted {
color: #fff;
background-color: #777777;
border-color: #555555;
background-color: #898b8d;
border-color: #6b6e71;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td.selected:focus,
.datepicker table tr td.selected.highlighted:focus,
.datepicker table tr td.selected.focus,
.datepicker table tr td.selected.highlighted.focus {
.datepicker table tr td.selected:focus, .datepicker table tr td.selected.focus, .datepicker table tr td.selected.highlighted:focus, .datepicker table tr td.selected.highlighted.focus {
color: #fff;
background-color: #5e5e5e;
border-color: #161616;
background-color: #959798;
border-color: #909295;
}
.datepicker table tr td.selected:hover,
.datepicker table tr td.selected.highlighted:hover {
.datepicker table tr td.selected:hover, .datepicker table tr td.selected.highlighted:hover {
color: #fff;
background-color: #5e5e5e;
border-color: #373737;
background-color: #c4c5c6;
border-color: #7d7f82;
}
.datepicker table tr td.selected:active,
.datepicker table tr td.selected.highlighted:active,
.datepicker table tr td.selected.active,
.datepicker table tr td.selected.highlighted.active {
.datepicker table tr td.selected:active, .datepicker table tr td.selected.active, .datepicker table tr td.selected.highlighted:active, .datepicker table tr td.selected.highlighted.active {
color: #fff;
background-color: #5e5e5e;
border-color: #373737;
background-color: #959798;
border-color: #7d7f82;
}
.datepicker table tr td.selected:active:hover,
.datepicker table tr td.selected.highlighted:active:hover,
.datepicker table tr td.selected.active:hover,
.datepicker table tr td.selected.highlighted.active:hover,
.datepicker table tr td.selected:active:focus,
.datepicker table tr td.selected.highlighted:active:focus,
.datepicker table tr td.selected.active:focus,
.datepicker table tr td.selected.highlighted.active:focus,
.datepicker table tr td.selected:active.focus,
.datepicker table tr td.selected.highlighted:active.focus,
.datepicker table tr td.selected.active.focus,
.datepicker table tr td.selected.highlighted.active.focus {
.datepicker table tr td.selected:active:hover, .datepicker table tr td.selected:active:focus, .datepicker table tr td.selected:active.focus, .datepicker table tr td.selected.active:hover, .datepicker table tr td.selected.active:focus, .datepicker table tr td.selected.active.focus, .datepicker table tr td.selected.highlighted:active:hover, .datepicker table tr td.selected.highlighted:active:focus, .datepicker table tr td.selected.highlighted:active.focus, .datepicker table tr td.selected.highlighted.active:hover, .datepicker table tr td.selected.highlighted.active:focus, .datepicker table tr td.selected.highlighted.active.focus {
color: #fff;
background-color: #4c4c4c;
border-color: #161616;
background-color: #9d9fa0;
border-color: #909295;
}
.datepicker table tr td.selected.disabled:hover,
.datepicker table tr td.selected.highlighted.disabled:hover,
.datepicker table tr td.selected[disabled]:hover,
.datepicker table tr td.selected.highlighted[disabled]:hover,
.datepicker table tr td.selected.disabled:hover, .datepicker table tr td.selected.disabled:focus, .datepicker table tr td.selected.disabled.focus, .datepicker table tr td.selected[disabled]:hover, .datepicker table tr td.selected[disabled]:focus, .datepicker table tr td.selected[disabled].focus,
fieldset[disabled] .datepicker table tr td.selected:hover,
fieldset[disabled] .datepicker table tr td.selected.highlighted:hover,
.datepicker table tr td.selected.disabled:focus,
.datepicker table tr td.selected.highlighted.disabled:focus,
.datepicker table tr td.selected[disabled]:focus,
.datepicker table tr td.selected.highlighted[disabled]:focus,
fieldset[disabled] .datepicker table tr td.selected:focus,
fieldset[disabled] .datepicker table tr td.selected.focus, .datepicker table tr td.selected.highlighted.disabled:hover, .datepicker table tr td.selected.highlighted.disabled:focus, .datepicker table tr td.selected.highlighted.disabled.focus, .datepicker table tr td.selected.highlighted[disabled]:hover, .datepicker table tr td.selected.highlighted[disabled]:focus, .datepicker table tr td.selected.highlighted[disabled].focus,
fieldset[disabled] .datepicker table tr td.selected.highlighted:hover,
fieldset[disabled] .datepicker table tr td.selected.highlighted:focus,
.datepicker table tr td.selected.disabled.focus,
.datepicker table tr td.selected.highlighted.disabled.focus,
.datepicker table tr td.selected[disabled].focus,
.datepicker table tr td.selected.highlighted[disabled].focus,
fieldset[disabled] .datepicker table tr td.selected.focus,
fieldset[disabled] .datepicker table tr td.selected.highlighted.focus {
background-color: #777777;
border-color: #555555;
background-color: #898b8d;
border-color: #6b6e71;
}
.datepicker table tr td.active,
.datepicker table tr td.active.highlighted {
.datepicker table tr td.active, .datepicker table tr td.active.highlighted {
color: #fff;
background-color: #337ab7;
border-color: #2e6da4;
background-color: #007bff;
border-color: #0277f4;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td.active:focus,
.datepicker table tr td.active.highlighted:focus,
.datepicker table tr td.active.focus,
.datepicker table tr td.active.highlighted.focus {
.datepicker table tr td.active:focus, .datepicker table tr td.active.focus, .datepicker table tr td.active.highlighted:focus, .datepicker table tr td.active.highlighted.focus {
color: #fff;
background-color: #286090;
border-color: #122b40;
background-color: #1a88ff;
border-color: #4199f7;
}
.datepicker table tr td.active:hover,
.datepicker table tr td.active.highlighted:hover {
.datepicker table tr td.active:hover, .datepicker table tr td.active.highlighted:hover {
color: #fff;
background-color: #286090;
border-color: #204d74;
background-color: #80bdff;
border-color: #2087f5;
}
.datepicker table tr td.active:active,
.datepicker table tr td.active.highlighted:active,
.datepicker table tr td.active.active,
.datepicker table tr td.active.highlighted.active {
.datepicker table tr td.active:active, .datepicker table tr td.active.active, .datepicker table tr td.active.highlighted:active, .datepicker table tr td.active.highlighted.active {
color: #fff;
background-color: #286090;
border-color: #204d74;
background-color: #1a88ff;
border-color: #2087f5;
}
.datepicker table tr td.active:active:hover,
.datepicker table tr td.active.highlighted:active:hover,
.datepicker table tr td.active.active:hover,
.datepicker table tr td.active.highlighted.active:hover,
.datepicker table tr td.active:active:focus,
.datepicker table tr td.active.highlighted:active:focus,
.datepicker table tr td.active.active:focus,
.datepicker table tr td.active.highlighted.active:focus,
.datepicker table tr td.active:active.focus,
.datepicker table tr td.active.highlighted:active.focus,
.datepicker table tr td.active.active.focus,
.datepicker table tr td.active.highlighted.active.focus {
.datepicker table tr td.active:active:hover, .datepicker table tr td.active:active:focus, .datepicker table tr td.active:active.focus, .datepicker table tr td.active.active:hover, .datepicker table tr td.active.active:focus, .datepicker table tr td.active.active.focus, .datepicker table tr td.active.highlighted:active:hover, .datepicker table tr td.active.highlighted:active:focus, .datepicker table tr td.active.highlighted:active.focus, .datepicker table tr td.active.highlighted.active:hover, .datepicker table tr td.active.highlighted.active:focus, .datepicker table tr td.active.highlighted.active.focus {
color: #fff;
background-color: #204d74;
border-color: #122b40;
background-color: #2b91ff;
border-color: #4199f7;
}
.datepicker table tr td.active.disabled:hover,
.datepicker table tr td.active.highlighted.disabled:hover,
.datepicker table tr td.active[disabled]:hover,
.datepicker table tr td.active.highlighted[disabled]:hover,
.datepicker table tr td.active.disabled:hover, .datepicker table tr td.active.disabled:focus, .datepicker table tr td.active.disabled.focus, .datepicker table tr td.active[disabled]:hover, .datepicker table tr td.active[disabled]:focus, .datepicker table tr td.active[disabled].focus,
fieldset[disabled] .datepicker table tr td.active:hover,
fieldset[disabled] .datepicker table tr td.active.highlighted:hover,
.datepicker table tr td.active.disabled:focus,
.datepicker table tr td.active.highlighted.disabled:focus,
.datepicker table tr td.active[disabled]:focus,
.datepicker table tr td.active.highlighted[disabled]:focus,
fieldset[disabled] .datepicker table tr td.active:focus,
fieldset[disabled] .datepicker table tr td.active.focus, .datepicker table tr td.active.highlighted.disabled:hover, .datepicker table tr td.active.highlighted.disabled:focus, .datepicker table tr td.active.highlighted.disabled.focus, .datepicker table tr td.active.highlighted[disabled]:hover, .datepicker table tr td.active.highlighted[disabled]:focus, .datepicker table tr td.active.highlighted[disabled].focus,
fieldset[disabled] .datepicker table tr td.active.highlighted:hover,
fieldset[disabled] .datepicker table tr td.active.highlighted:focus,
.datepicker table tr td.active.disabled.focus,
.datepicker table tr td.active.highlighted.disabled.focus,
.datepicker table tr td.active[disabled].focus,
.datepicker table tr td.active.highlighted[disabled].focus,
fieldset[disabled] .datepicker table tr td.active.focus,
fieldset[disabled] .datepicker table tr td.active.highlighted.focus {
background-color: #337ab7;
border-color: #2e6da4;
background-color: #007bff;
border-color: #0277f4;
}
.datepicker table tr td span {
display: block;
width: 23%;
@@ -507,172 +447,127 @@ fieldset[disabled] .datepicker table tr td.active.highlighted.focus {
cursor: pointer;
border-radius: 4px;
}
.datepicker table tr td span:hover,
.datepicker table tr td span.focused {
background: #eeeeee;
.datepicker table tr td span:hover, .datepicker table tr td span.focused {
color: #212529;
background: #e9e9ea;
}
.datepicker table tr td span.disabled,
.datepicker table tr td span.disabled:hover {
.datepicker table tr td span.disabled, .datepicker table tr td span.disabled:hover {
background: none;
color: #777777;
color: #6c757d;
cursor: default;
}
.datepicker table tr td span.active,
.datepicker table tr td span.active:hover,
.datepicker table tr td span.active.disabled,
.datepicker table tr td span.active.disabled:hover {
.datepicker table tr td span.active, .datepicker table tr td span.active:hover, .datepicker table tr td span.active.disabled, .datepicker table tr td span.active.disabled:hover {
color: #fff;
background-color: #337ab7;
border-color: #2e6da4;
background-color: #007bff;
border-color: #0277f4;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td span.active:focus,
.datepicker table tr td span.active:hover:focus,
.datepicker table tr td span.active.disabled:focus,
.datepicker table tr td span.active.disabled:hover:focus,
.datepicker table tr td span.active.focus,
.datepicker table tr td span.active:hover.focus,
.datepicker table tr td span.active.disabled.focus,
.datepicker table tr td span.active.disabled:hover.focus {
.datepicker table tr td span.active:focus, .datepicker table tr td span.active.focus, .datepicker table tr td span.active:hover:focus, .datepicker table tr td span.active:hover.focus, .datepicker table tr td span.active.disabled:focus, .datepicker table tr td span.active.disabled.focus, .datepicker table tr td span.active.disabled:hover:focus, .datepicker table tr td span.active.disabled:hover.focus {
color: #fff;
background-color: #286090;
border-color: #122b40;
background-color: #1a88ff;
border-color: #4199f7;
}
.datepicker table tr td span.active:hover,
.datepicker table tr td span.active:hover:hover,
.datepicker table tr td span.active.disabled:hover,
.datepicker table tr td span.active.disabled:hover:hover {
.datepicker table tr td span.active:hover, .datepicker table tr td span.active:hover:hover, .datepicker table tr td span.active.disabled:hover, .datepicker table tr td span.active.disabled:hover:hover {
color: #fff;
background-color: #286090;
border-color: #204d74;
background-color: #80bdff;
border-color: #2087f5;
}
.datepicker table tr td span.active:active,
.datepicker table tr td span.active:hover:active,
.datepicker table tr td span.active.disabled:active,
.datepicker table tr td span.active.disabled:hover:active,
.datepicker table tr td span.active.active,
.datepicker table tr td span.active:hover.active,
.datepicker table tr td span.active.disabled.active,
.datepicker table tr td span.active.disabled:hover.active {
.datepicker table tr td span.active:active, .datepicker table tr td span.active.active, .datepicker table tr td span.active:hover:active, .datepicker table tr td span.active:hover.active, .datepicker table tr td span.active.disabled:active, .datepicker table tr td span.active.disabled.active, .datepicker table tr td span.active.disabled:hover:active, .datepicker table tr td span.active.disabled:hover.active {
color: #fff;
background-color: #286090;
border-color: #204d74;
background-color: #1a88ff;
border-color: #2087f5;
}
.datepicker table tr td span.active:active:hover,
.datepicker table tr td span.active:hover:active:hover,
.datepicker table tr td span.active.disabled:active:hover,
.datepicker table tr td span.active.disabled:hover:active:hover,
.datepicker table tr td span.active.active:hover,
.datepicker table tr td span.active:hover.active:hover,
.datepicker table tr td span.active.disabled.active:hover,
.datepicker table tr td span.active.disabled:hover.active:hover,
.datepicker table tr td span.active:active:focus,
.datepicker table tr td span.active:hover:active:focus,
.datepicker table tr td span.active.disabled:active:focus,
.datepicker table tr td span.active.disabled:hover:active:focus,
.datepicker table tr td span.active.active:focus,
.datepicker table tr td span.active:hover.active:focus,
.datepicker table tr td span.active.disabled.active:focus,
.datepicker table tr td span.active.disabled:hover.active:focus,
.datepicker table tr td span.active:active.focus,
.datepicker table tr td span.active:hover:active.focus,
.datepicker table tr td span.active.disabled:active.focus,
.datepicker table tr td span.active.disabled:hover:active.focus,
.datepicker table tr td span.active.active.focus,
.datepicker table tr td span.active:hover.active.focus,
.datepicker table tr td span.active.disabled.active.focus,
.datepicker table tr td span.active.disabled:hover.active.focus {
.datepicker table tr td span.active:active:hover, .datepicker table tr td span.active:active:focus, .datepicker table tr td span.active:active.focus, .datepicker table tr td span.active.active:hover, .datepicker table tr td span.active.active:focus, .datepicker table tr td span.active.active.focus, .datepicker table tr td span.active:hover:active:hover, .datepicker table tr td span.active:hover:active:focus, .datepicker table tr td span.active:hover:active.focus, .datepicker table tr td span.active:hover.active:hover, .datepicker table tr td span.active:hover.active:focus, .datepicker table tr td span.active:hover.active.focus, .datepicker table tr td span.active.disabled:active:hover, .datepicker table tr td span.active.disabled:active:focus, .datepicker table tr td span.active.disabled:active.focus, .datepicker table tr td span.active.disabled.active:hover, .datepicker table tr td span.active.disabled.active:focus, .datepicker table tr td span.active.disabled.active.focus, .datepicker table tr td span.active.disabled:hover:active:hover, .datepicker table tr td span.active.disabled:hover:active:focus, .datepicker table tr td span.active.disabled:hover:active.focus, .datepicker table tr td span.active.disabled:hover.active:hover, .datepicker table tr td span.active.disabled:hover.active:focus, .datepicker table tr td span.active.disabled:hover.active.focus {
color: #fff;
background-color: #204d74;
border-color: #122b40;
background-color: #2b91ff;
border-color: #4199f7;
}
.datepicker table tr td span.active.disabled:hover,
.datepicker table tr td span.active:hover.disabled:hover,
.datepicker table tr td span.active.disabled.disabled:hover,
.datepicker table tr td span.active.disabled:hover.disabled:hover,
.datepicker table tr td span.active[disabled]:hover,
.datepicker table tr td span.active:hover[disabled]:hover,
.datepicker table tr td span.active.disabled[disabled]:hover,
.datepicker table tr td span.active.disabled:hover[disabled]:hover,
.datepicker table tr td span.active.disabled:hover, .datepicker table tr td span.active.disabled:focus, .datepicker table tr td span.active.disabled.focus, .datepicker table tr td span.active[disabled]:hover, .datepicker table tr td span.active[disabled]:focus, .datepicker table tr td span.active[disabled].focus,
fieldset[disabled] .datepicker table tr td span.active:hover,
fieldset[disabled] .datepicker table tr td span.active:hover:hover,
fieldset[disabled] .datepicker table tr td span.active.disabled:hover,
fieldset[disabled] .datepicker table tr td span.active.disabled:hover:hover,
.datepicker table tr td span.active.disabled:focus,
.datepicker table tr td span.active:hover.disabled:focus,
.datepicker table tr td span.active.disabled.disabled:focus,
.datepicker table tr td span.active.disabled:hover.disabled:focus,
.datepicker table tr td span.active[disabled]:focus,
.datepicker table tr td span.active:hover[disabled]:focus,
.datepicker table tr td span.active.disabled[disabled]:focus,
.datepicker table tr td span.active.disabled:hover[disabled]:focus,
fieldset[disabled] .datepicker table tr td span.active:focus,
fieldset[disabled] .datepicker table tr td span.active.focus, .datepicker table tr td span.active:hover.disabled:hover, .datepicker table tr td span.active:hover.disabled:focus, .datepicker table tr td span.active:hover.disabled.focus, .datepicker table tr td span.active:hover[disabled]:hover, .datepicker table tr td span.active:hover[disabled]:focus, .datepicker table tr td span.active:hover[disabled].focus,
fieldset[disabled] .datepicker table tr td span.active:hover:hover,
fieldset[disabled] .datepicker table tr td span.active:hover:focus,
fieldset[disabled] .datepicker table tr td span.active:hover.focus, .datepicker table tr td span.active.disabled.disabled:hover, .datepicker table tr td span.active.disabled.disabled:focus, .datepicker table tr td span.active.disabled.disabled.focus, .datepicker table tr td span.active.disabled[disabled]:hover, .datepicker table tr td span.active.disabled[disabled]:focus, .datepicker table tr td span.active.disabled[disabled].focus,
fieldset[disabled] .datepicker table tr td span.active.disabled:hover,
fieldset[disabled] .datepicker table tr td span.active.disabled:focus,
fieldset[disabled] .datepicker table tr td span.active.disabled.focus, .datepicker table tr td span.active.disabled:hover.disabled:hover, .datepicker table tr td span.active.disabled:hover.disabled:focus, .datepicker table tr td span.active.disabled:hover.disabled.focus, .datepicker table tr td span.active.disabled:hover[disabled]:hover, .datepicker table tr td span.active.disabled:hover[disabled]:focus, .datepicker table tr td span.active.disabled:hover[disabled].focus,
fieldset[disabled] .datepicker table tr td span.active.disabled:hover:hover,
fieldset[disabled] .datepicker table tr td span.active.disabled:hover:focus,
.datepicker table tr td span.active.disabled.focus,
.datepicker table tr td span.active:hover.disabled.focus,
.datepicker table tr td span.active.disabled.disabled.focus,
.datepicker table tr td span.active.disabled:hover.disabled.focus,
.datepicker table tr td span.active[disabled].focus,
.datepicker table tr td span.active:hover[disabled].focus,
.datepicker table tr td span.active.disabled[disabled].focus,
.datepicker table tr td span.active.disabled:hover[disabled].focus,
fieldset[disabled] .datepicker table tr td span.active.focus,
fieldset[disabled] .datepicker table tr td span.active:hover.focus,
fieldset[disabled] .datepicker table tr td span.active.disabled.focus,
fieldset[disabled] .datepicker table tr td span.active.disabled:hover.focus {
background-color: #337ab7;
border-color: #2e6da4;
background-color: #007bff;
border-color: #0277f4;
}
.datepicker table tr td span.old,
.datepicker table tr td span.new {
color: #777777;
.datepicker table tr td span.old, .datepicker table tr td span.new {
color: #6c757d;
}
.datepicker .datepicker-switch {
width: 145px;
}
.datepicker .datepicker-switch,
.datepicker .prev,
.datepicker .next,
.datepicker tfoot tr th {
cursor: pointer;
}
.datepicker .datepicker-switch:hover,
.datepicker .prev:hover,
.datepicker .next:hover,
.datepicker tfoot tr th:hover {
background: #eeeeee;
color: #212529;
background: #e9e9ea;
}
.datepicker .prev.disabled, .datepicker .next.disabled {
visibility: hidden;
}
.datepicker .cw {
font-size: 10px;
width: 12px;
padding: 0 2px 0 5px;
vertical-align: middle;
}
.input-group.date .input-group-addon {
cursor: pointer;
}
.input-daterange {
width: 100%;
}
.input-daterange input {
text-align: center;
}
.input-daterange input:first-child {
border-radius: 3px 0 0 3px;
}
.input-daterange input:last-child {
border-radius: 0 3px 3px 0;
}
.input-daterange .input-group-addon {
width: auto;
min-width: 16px;
padding: 4px 5px;
line-height: 1.42857143;
text-shadow: 0 1px 0 #fff;
line-height: 1.5;
border-width: 1px 0;
margin-left: -5px;
margin-right: -5px;
}
/*# sourceMappingURL=bootstrap-datepicker3.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
!function(a){a.fn.datepicker.dates["en-CA"]={days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],daysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],daysMin:["Su","Mo","Tu","We","Th","Fr","Sa"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],today:"Today",monthsTitle:"Months",clear:"Clear",weekStart:0,format:"yyyy-mm-dd"},a.fn.datepicker.deprecated("This filename doesn't follow the convention, use bootstrap-datepicker.en-CA.js instead.")}(jQuery);

View File

@@ -0,0 +1 @@
!function(a){a.fn.datepicker.dates["ar-tn"]={days:["الأحد","الاثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت","الأحد"],daysShort:["أحد","اثنين","ثلاثاء","أربعاء","خميس","جمعة","سبت","أحد"],daysMin:["ح","ن","ث","ع","خ","ج","س","ح"],months:["جانفي","فيفري","مارس","أفريل","ماي","جوان","جويليه","أوت","سبتمبر","أكتوبر","نوفمبر","ديسمبر"],monthsShort:["جانفي","فيفري","مارس","أفريل","ماي","جوان","جويليه","أوت","سبتمبر","أكتوبر","نوفمبر","ديسمبر"],today:"هذا اليوم",rtl:!0}}(jQuery);

View File

@@ -1 +1 @@
!function(a){a.fn.datepicker.dates.az={days:["Bazar","Bazar ertəsi","Çərşənbə axşamı","Çərşənbə","Cümə axşamı","Cümə","Şənbə"],daysShort:["B.","B.e","Ç.a","Ç.","C.a","C.","Ş."],daysMin:["B.","B.e","Ç.a","Ç.","C.a","C.","Ş."],months:["Yanvar","Fevral","Mart","Aprel","May","İyun","İyul","Avqust","Sentyabr","Oktyabr","Noyabr","Dekabr"],monthsShort:["Yan","Fev","Mar","Apr","May","İyun","İyul","Avq","Sen","Okt","Noy","Dek"],today:"Bu gün",weekStart:1}}(jQuery);
!function(a){a.fn.datepicker.dates.az={days:["Bazar","Bazar ertəsi","Çərşənbə axşamı","Çərşənbə","Cümə axşamı","Cümə","Şənbə"],daysShort:["B.","B.e","Ç.a","Ç.","C.a","C.","Ş."],daysMin:["B.","B.e","Ç.a","Ç.","C.a","C.","Ş."],months:["Yanvar","Fevral","Mart","Aprel","May","İyun","İyul","Avqust","Sentyabr","Oktyabr","Noyabr","Dekabr"],monthsShort:["Yan","Fev","Mar","Apr","May","İyun","İyul","Avq","Sen","Okt","Noy","Dek"],today:"Bu gün",weekStart:1,clear:"Təmizlə",monthsTitle:"Aylar"}}(jQuery);

View File

@@ -0,0 +1 @@
!function(a){a.fn.datepicker.dates.bm={days:["Kari","Ntɛnɛn","Tarata","Araba","Alamisa","Juma","Sibiri"],daysShort:["Kar","Ntɛ","Tar","Ara","Ala","Jum","Sib"],daysMin:["Ka","Nt","Ta","Ar","Al","Ju","Si"],months:["Zanwuyekalo","Fewuruyekalo","Marisikalo","Awirilikalo","Mɛkalo","Zuwɛnkalo","Zuluyekalo","Utikalo","Sɛtanburukalo","ɔkutɔburukalo","Nowanburukalo","Desanburukalo"],monthsShort:["Zan","Few","Mar","Awi","Mɛ","Zuw","Zul","Uti","Sɛt","ɔku","Now","Des"],today:"Bi",monthsTitle:"Kalo",clear:"Ka jɔsi",weekStart:1,format:"dd/mm/yyyy"}}(jQuery);

View File

@@ -0,0 +1 @@
!function(a){a.fn.datepicker.dates.bn={days:["রবিবার","সোমবার","মঙ্গলবার","বুধবার","বৃহস্পতিবার","শুক্রবার","শনিবার"],daysShort:["রবিবার","সোমবার","মঙ্গলবার","বুধবার","বৃহস্পতিবার","শুক্রবার","শনিবার"],daysMin:["রবি","সোম","মঙ্গল","বুধ","বৃহস্পতি","শুক্র","শনি"],months:["জানুয়ারী","ফেব্রুয়ারি","মার্চ","এপ্রিল","মে","জুন","জুলাই","অগাস্ট","সেপ্টেম্বর","অক্টোবর","নভেম্বর","ডিসেম্বর"],monthsShort:["জানুয়ারী","ফেব্রুয়ারি","মার্চ","এপ্রিল","মে","জুন","জুলাই","অগাস্ট","সেপ্টেম্বর","অক্টোবর","নভেম্বর","ডিসেম্বর"],today:"আজ",monthsTitle:"মাস",clear:"পরিষ্কার",weekStart:0,format:"mm/dd/yyyy"}}(jQuery);

View File

@@ -0,0 +1 @@
!function(a){a.fn.datepicker.dates.br={days:["Sul","Lun","Meurzh","Merc'her","Yaou","Gwener","Sadorn"],daysShort:["Sul","Lun","Meu.","Mer.","Yao.","Gwe.","Sad."],daysMin:["Su","L","Meu","Mer","Y","G","Sa"],months:["Genver","C'hwevrer","Meurzh","Ebrel","Mae","Mezheven","Gouere","Eost","Gwengolo","Here","Du","Kerzu"],monthsShort:["Genv.","C'hw.","Meur.","Ebre.","Mae","Mezh.","Goue.","Eost","Gwen.","Here","Du","Kerz."],today:"Hiziv",monthsTitle:"Miz",clear:"Dilemel",weekStart:1,format:"dd/mm/yyyy"}}(jQuery);

View File

@@ -1 +1 @@
!function(a){a.fn.datepicker.dates.cs={days:["Neděle","Pondělí","Úterý","Středa","Čtvrtek","Pátek","Sobota"],daysShort:["Ned","Pon","Úte","Stř","Čtv","Pát","Sob"],daysMin:["Ne","Po","Út","St","Čt","Pá","So"],months:["Leden","Únor","Březen","Duben","Květen","Červen","Červenec","Srpen","Září","Říjen","Listopad","Prosinec"],monthsShort:["Led","Úno","Bře","Dub","Kvě","Čer","Čnc","Srp","Zář","Říj","Lis","Pro"],today:"Dnes",clear:"Vymazat",weekStart:1,format:"dd.m.yyyy"}}(jQuery);
!function(a){a.fn.datepicker.dates.cs={days:["Neděle","Pondělí","Úterý","Středa","Čtvrtek","Pátek","Sobota"],daysShort:["Ned","Pon","Úte","Stř","Čtv","Pát","Sob"],daysMin:["Ne","Po","Út","St","Čt","Pá","So"],months:["Leden","Únor","Březen","Duben","Květen","Červen","Červenec","Srpen","Září","Říjen","Listopad","Prosinec"],monthsShort:["Led","Úno","Bře","Dub","Kvě","Čer","Čnc","Srp","Zář","Říj","Lis","Pro"],today:"Dnes",clear:"Vymazat",monthsTitle:"Měsíc",weekStart:1,format:"dd.mm.yyyy"}}(jQuery);

View File

@@ -1 +1 @@
!function(a){a.fn.datepicker.dates.da={days:["søndag","mandag","tirsdag","onsdag","torsdag","fredag","lørdag"],daysShort:["søn","man","tir","ons","tor","fre","lør"],daysMin:["sø","ma","ti","on","to","fr","lø"],months:["januar","februar","marts","april","maj","juni","juli","august","september","oktober","november","december"],monthsShort:["jan","feb","mar","apr","maj","jun","jul","aug","sep","okt","nov","dec"],today:"I Dag",clear:"Nulstil"}}(jQuery);
!function(a){a.fn.datepicker.dates.da={days:["Søndag","Mandag","Tirsdag","Onsdag","Torsdag","Fredag","Lørdag"],daysShort:["Søn","Man","Tir","Ons","Tor","Fre","Lør"],daysMin:["Sø","Ma","Ti","On","To","Fr","Lø"],months:["Januar","Februar","Marts","April","Maj","Juni","Juli","August","September","Oktober","November","December"],monthsShort:["Jan","Feb","Mar","Apr","Maj","Jun","Jul","Aug","Sep","Okt","Nov","Dec"],today:"I Dag",weekStart:1,clear:"Nulstil",format:"dd/mm/yyyy",monthsTitle:"Måneder"}}(jQuery);

View File

@@ -0,0 +1 @@
!function(a){a.fn.datepicker.dates["en-CA"]={days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],daysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],daysMin:["Su","Mo","Tu","We","Th","Fr","Sa"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],today:"Today",monthsTitle:"Months",clear:"Clear",weekStart:0,format:"yyyy-mm-dd"}}(jQuery);

View File

@@ -0,0 +1 @@
!function(a){a.fn.datepicker.dates["en-IE"]={days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],daysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],daysMin:["Su","Mo","Tu","We","Th","Fr","Sa"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],today:"Today",monthsTitle:"Months",clear:"Clear",weekStart:1,format:"dd/mm/yyyy"}}(jQuery);

View File

@@ -0,0 +1 @@
!function(a){a.fn.datepicker.dates["en-NZ"]={days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],daysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],daysMin:["Su","Mo","Tu","We","Th","Fr","Sa"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],today:"Today",monthsTitle:"Months",clear:"Clear",weekStart:1,format:"d/mm/yyyy"}}(jQuery);

View File

@@ -0,0 +1 @@
!function(a){a.fn.datepicker.dates["en-ZA"]={days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],daysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],daysMin:["Su","Mo","Tu","We","Th","Fr","Sa"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],today:"Today",monthsTitle:"Months",clear:"Clear",weekStart:1,format:"yyyy/mm/d"}}(jQuery);

View File

@@ -1 +1 @@
!function(a){a.fn.datepicker.dates.eu={days:["Igandea","Astelehena","Asteartea","Asteazkena","Osteguna","Ostirala","Larunbata"],daysShort:["Ig","Al","Ar","Az","Og","Ol","Lr"],daysMin:["Ig","Al","Ar","Az","Og","Ol","Lr"],months:["Urtarrila","Otsaila","Martxoa","Apirila","Maiatza","Ekaina","Uztaila","Abuztua","Iraila","Urria","Azaroa","Abendua"],monthsShort:["Urt","Ots","Mar","Api","Mai","Eka","Uzt","Abu","Ira","Urr","Aza","Abe"],today:"Gaur"}}(jQuery);
!function(a){a.fn.datepicker.dates.eu={days:["Igandea","Astelehena","Asteartea","Asteazkena","Osteguna","Ostirala","Larunbata"],daysShort:["Ig","Al","Ar","Az","Og","Ol","Lr"],daysMin:["Ig","Al","Ar","Az","Og","Ol","Lr"],months:["Urtarrila","Otsaila","Martxoa","Apirila","Maiatza","Ekaina","Uztaila","Abuztua","Iraila","Urria","Azaroa","Abendua"],monthsShort:["Urt","Ots","Mar","Api","Mai","Eka","Uzt","Abu","Ira","Urr","Aza","Abe"],today:"Gaur",monthsTitle:"Hilabeteak",clear:"Ezabatu",weekStart:1,format:"yyyy/mm/dd"}}(jQuery);

View File

@@ -0,0 +1 @@
!function(a){a.fn.datepicker.dates.hi={days:["रविवार","सोमवार","मंगलवार","बुधवार","गुरुवार","शुक्रवार","शनिवार"],daysShort:["सूर्य","सोम","मंगल","बुध","गुरु","शुक्र","शनि"],daysMin:["र","सो","मं","बु","गु","शु","श"],months:["जनवरी","फ़रवरी","मार्च","अप्रैल","मई","जून","जुलाई","अगस्त","सितम्बर","अक्टूबर","नवंबर","दिसम्बर"],monthsShort:["जन","फ़रवरी","मार्च","अप्रैल","मई","जून","जुलाई","अगस्त","सितं","अक्टूबर","नवं","दिसम्बर"],today:"आज",monthsTitle:"महीने",clear:"साफ",weekStart:1,format:"dd / mm / yyyy"}}(jQuery);

View File

@@ -1 +1 @@
!function(a){a.fn.datepicker.dates.hy={days:["Կիրակի","Երկուշաբթի","Երեքշաբթի","Չորեքշաբթի","Հինգշաբթի","Ուրբաթ","Շաբաթ"],daysShort:["Կրկ","Երկ","Երք","Չրք","Հնգ","Ուր","Շբթ"],daysMin:["Կրկ",րկ",րք",րք",նգ","Ուր",բթ"],months:["Հունվար","Փետրվար","Մարտ","Ապրիլ","Մայիս","Հունիս","Հուլիս","Օգոստոս","Սեպտեմբեր","Հոկտեմբեր","Նոյեմբեր","Դեկտեմբեր"],monthsShort:[ուն","Փետ","Մար","Ապր","Մայ","Հնս","Հլս","Օգս","Սեպ","Հոկ",մբ","Դեկ"],today:"Այսօր",clear:"Ջնջել",format:"dd.mm.yyyy",weekStart:1}}(jQuery);
!function(a){a.fn.datepicker.dates.hy={days:["Կիրակի","Երկուշաբթի","Երեքշաբթի","Չորեքշաբթի","Հինգշաբթի","Ուրբաթ","Շաբաթ"],daysShort:["Կիր","Երկ","Երե",որ",ին","Ուրբ",աբ"],daysMin:["Կի","Եկ","Եք",ո",ի","Ու",ա"],months:["Հունվար","Փետրվար","Մարտ","Ապրիլ","Մայիս","Հունիս","Հուլիս","Օգոստոս","Սեպտեմբեր","Հոկտեմբեր","Նոյեմբեր","Դեկտեմբեր"],monthsShort:["Հնվ","Փետ","Մար","Ապր","Մայ",ուն",ուլ","Օգս","Սեպ","Հոկ",ոյ","Դեկ"],today:"Այսօր",clear:"Ջնջել",format:"dd.mm.yyyy",weekStart:1,monthsTitle:"Ամիսնէր"}}(jQuery);

View File

@@ -1 +1 @@
!function(a){a.fn.datepicker.dates.ka={days:["კვირა","ორშაბათი","სამშაბათი","ოთხშაბათი","ხუთშაბათი","პარასკევი","შაბათი"],daysShort:["კვი","ორშ","სამ","ოთხ","ხუთ","პარ","შაბ"],daysMin:["კვ","ორ","სა","ოთ","ხუ","პა","შა"],months:["იანვარი","თებერვალი","მარტი","აპრილი","მაისი","ივნისი","ივლისი","აგვისტო","სექტემბერი","ოქტომბი","ნოემბერი","დეკემბერი"],monthsShort:["იან","თებ","მარ","აპრ","მაი","ივნ","ივლ","აგვ","სექ","ოქტ","ნოე","დეკ"],today:"დღეს",clear:"გასუფთავება",weekStart:1,format:"dd.mm.yyyy"}}(jQuery);
!function(a){a.fn.datepicker.dates.ka={days:["კვირა","ორშაბათი","სამშაბათი","ოთხშაბათი","ხუთშაბათი","პარასკევი","შაბათი"],daysShort:["კვი","ორშ","სამ","ოთხ","ხუთ","პარ","შაბ"],daysMin:["კვ","ორ","სა","ოთ","ხუ","პა","შა"],months:["იანვარი","თებერვალი","მარტი","აპრილი","მაისი","ივნისი","ივლისი","აგვისტო","სექტემბერი","ოქტომბერი","ნოემბერი","დეკემბერი"],monthsShort:["იან","თებ","მარ","აპრ","მაი","ივნ","ივლ","აგვ","სექ","ოქტ","ნოე","დეკ"],today:"დღეს",clear:"გასუფთავება",weekStart:1,format:"dd.mm.yyyy"}}(jQuery);

View File

@@ -1 +1 @@
!function(a){a.fn.datepicker.dates.kh={days:["អាទិត្យ","ចន្ទ","អង្គារ","ពុធ","ព្រហស្បតិ៍","សុក្រ","សៅរ៍","អាទិត្យ"],daysShort:["អា.ទិ","ចន្ទ","អង្គារ","ពុធ","ព្រ.ហ","សុក្រ","សៅរ៍","អា.ទិ"],daysMin:["អា.ទិ","ចន្ទ","អង្គារ","ពុធ","ព្រ.ហ","សុក្រ","សៅរ៍","អា.ទិ"],months:["មករា","កុម្ភះ","មិនា","មេសា","ឧសភា","មិថុនា","កក្កដា","សីហា","កញ្ញា","តុលា","វិច្ឆិកា","ធ្នូ"],monthsShort:["មករា","កុម្ភះ","មិនា","មេសា","ឧសភា","មិថុនា","កក្កដា","សីហា","កញ្ញា","តុលា","វិច្ឆិកា","ធ្នូ"],today:"ថ្ងៃនេះ",clear:"សំអាត"}}(jQuery);
!function(a){a.fn.datepicker.dates.kh={days:["អាទិត្យ","ចន្ទ","អង្គារ","ពុធ","ព្រហស្បតិ៍","សុក្រ","សៅរ៍"],daysShort:["អា.ទិ","ចន្ទ","អង្គារ","ពុធ","ព្រ.ហ","សុក្រ","សៅរ៍"],daysMin:["អា.ទិ","ចន្ទ","អង្គារ","ពុធ","ព្រ.ហ","សុក្រ","សៅរ៍"],months:["មករា","កុម្ភះ","មិនា","មេសា","ឧសភា","មិថុនា","កក្កដា","សីហា","កញ្ញា","តុលា","វិច្ឆិកា","ធ្នូ"],monthsShort:["មករា","កុម្ភះ","មិនា","មេសា","ឧសភា","មិថុនា","កក្កដា","សីហា","កញ្ញា","តុលា","វិច្ឆិកា","ធ្នូ"],today:"ថ្ងៃនេះ",clear:"សំអាត"},a.fn.datepicker.deprecated('The language code "kh" is deprecated and will be removed in 2.0. For Khmer support use "km" instead.')}(jQuery);

View File

@@ -0,0 +1 @@
!function(a){a.fn.datepicker.dates.km={days:["អាទិត្យ","ចន្ទ","អង្គារ","ពុធ","ព្រហស្បតិ៍","សុក្រ","សៅរ៍"],daysShort:["អា.ទិ","ចន្ទ","អង្គារ","ពុធ","ព្រ.ហ","សុក្រ","សៅរ៍"],daysMin:["អា.ទិ","ចន្ទ","អង្គារ","ពុធ","ព្រ.ហ","សុក្រ","សៅរ៍"],months:["មករា","កុម្ភះ","មិនា","មេសា","ឧសភា","មិថុនា","កក្កដា","សីហា","កញ្ញា","តុលា","វិច្ឆិកា","ធ្នូ"],monthsShort:["មករា","កុម្ភះ","មិនា","មេសា","ឧសភា","មិថុនា","កក្កដា","សីហា","កញ្ញា","តុលា","វិច្ឆិកា","ធ្នូ"],today:"ថ្ងៃនេះ",clear:"សំអាត"}}(jQuery);

View File

@@ -1 +1 @@
!function(a){a.fn.datepicker.dates.kr={days:["일요일","월요일","화요일","수요일","목요일","금요일","토요일"],daysShort:["일","월","화","수","목","금","토"],daysMin:["일","월","화","수","목","금","토"],months:["1월","2월","3월","4월","5월","6월","7월","8월","9월","10월","11월","12월"],monthsShort:["1월","2월","3월","4월","5월","6월","7월","8월","9월","10월","11월","12월"]}}(jQuery);
!function(a){a.fn.datepicker.dates.kr={days:["일요일","월요일","화요일","수요일","목요일","금요일","토요일"],daysShort:["일","월","화","수","목","금","토"],daysMin:["일","월","화","수","목","금","토"],months:["1월","2월","3월","4월","5월","6월","7월","8월","9월","10월","11월","12월"],monthsShort:["1월","2월","3월","4월","5월","6월","7월","8월","9월","10월","11월","12월"]},a.fn.datepicker.deprecated('The language code "kr" is deprecated and will be removed in 2.0. For korean support use "ko" instead.')}(jQuery);

View File

@@ -1 +1 @@
!function(a){a.fn.datepicker.dates.lv={days:["Svētdiena","Pirmdiena","Otrdiena","Trešdiena","Ceturtdiena","Piektdiena","Sestdiena"],daysShort:["Sv","P","O","T","C","Pk","S"],daysMin:["Sv","Pr","Ot","Tr","Ce","Pk","Se"],months:["Janvāris","Februāris","Marts","Aprīlis","Maijs","Jūnijs","Jūlijs","Augusts","Septembris","Oktobris","Novembris","Decembris"],monthsShort:["Jan","Feb","Mar","Apr","Mai","Jūn","Jūl","Aug","Sep","Okt","Nov","Dec"],today:"Šodien",weekStart:1}}(jQuery);
!function(a){a.fn.datepicker.dates.lv={days:["Svētdiena","Pirmdiena","Otrdiena","Trešdiena","Ceturtdiena","Piektdiena","Sestdiena"],daysShort:["Sv","P","O","T","C","Pk","S"],daysMin:["Sv","Pr","Ot","Tr","Ce","Pk","Se"],months:["Janvāris","Februāris","Marts","Aprīlis","Maijs","Jūnijs","Jūlijs","Augusts","Septembris","Oktobris","Novembris","Decembris"],monthsShort:["Jan","Feb","Mar","Apr","Mai","Jūn","Jūl","Aug","Sep","Okt","Nov","Dec"],monthsTitle:"Mēneši",today:"Šodien",clear:"Nodzēst",weekStart:1}}(jQuery);

View File

@@ -1 +0,0 @@
!function(a){a.fn.datepicker.dates.nb={days:["Søndag","Mandag","Tirsdag","Onsdag","Torsdag","Fredag","Lørdag"],daysShort:["Søn","Man","Tir","Ons","Tor","Fre","Lør"],daysMin:["Sø","Ma","Ti","On","To","Fr","Lø"],months:["Januar","Februar","Mars","April","Mai","Juni","Juli","August","September","Oktober","November","Desember"],monthsShort:["Jan","Feb","Mar","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Des"],today:"I Dag",format:"dd.mm.yyyy"}}(jQuery);

View File

@@ -1 +1 @@
!function(a){a.fn.datepicker.dates.no={days:["Søndag","Mandag","Tirsdag","Onsdag","Torsdag","Fredag","Lørdag"],daysShort:["Søn","Man","Tir","Ons","Tor","Fre","Lør"],daysMin:["Sø","Ma","Ti","On","To","Fr","Lø"],months:["Januar","Februar","Mars","April","Mai","Juni","Juli","August","September","Oktober","November","Desember"],monthsShort:["Jan","Feb","Mar","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Des"],today:"I dag",clear:"Nullstill",weekStart:1,format:"dd.mm.yyyy"}}(jQuery);
!function(a){a.fn.datepicker.dates.no={days:["søndag","mandag","tirsdag","onsdag","torsdag","fredag","lørdag"],daysShort:["søn","man","tir","ons","tor","fre","lør"],daysMin:["sø","ma","ti","on","to","fr","lø"],months:["januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember"],monthsShort:["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des"],today:"i dag",monthsTitle:"Måneder",clear:"Nullstill",weekStart:1,format:"dd.mm.yyyy"}}(jQuery);

View File

@@ -0,0 +1 @@
!function(a){a.fn.datepicker.dates.oc={days:["Dimenge","Diluns","Dimars","Dimècres","Dijòus","Divendres","Dissabte"],daysShort:["Dim","Dil","Dmr","Dmc","Dij","Div","Dis"],daysMin:["dg","dl","dr","dc","dj","dv","ds"],months:["Genièr","Febrièr","Març","Abrial","Mai","Junh","Julhet","Agost","Setembre","Octobre","Novembre","Decembre"],monthsShort:["Gen","Feb","Mar","Abr","Mai","Jun","Jul","Ago","Set","Oct","Nov","Dec"],today:"Uèi",monthsTitle:"Meses",clear:"Escafar",weekStart:1,format:"dd/mm/yyyy"}}(jQuery);

View File

@@ -1 +1 @@
!function(a){a.fn.datepicker.dates.pl={days:["niedziela","poniedziałek","wtorek","środa","czwartek","piątek","sobota"],daysShort:["niedz.","pon.","wt.","śr.","czw.","piąt.","sob."],daysMin:["ndz.","pn.","wt.","śr.","czw.","pt.","sob."],months:["styczeń","luty","marzec","kwiecień","maj","czerwiec","lipiec","sierpień","wrzesień","październik","listopad","grudzień"],monthsShort:["sty.","lut.","mar.","kwi.","maj","cze.","lip.","sie.","wrz.","paź.","lis.","gru."],today:"dzisiaj",weekStart:1,clear:"wyczyść",format:"dd.mm.yyyy"}}(jQuery);
!function(a){a.fn.datepicker.dates.pl={days:["Niedziela","Poniedziałek","Wtorek","Środa","Czwartek","Piątek","Sobota"],daysShort:["Niedz.","Pon.","Wt.","Śr.","Czw.","Piąt.","Sob."],daysMin:["Ndz.","Pn.","Wt.","Śr.","Czw.","Pt.","Sob."],months:["Styczeń","Luty","Marzec","Kwiecień","Maj","Czerwiec","Lipiec","Sierpień","Wrzesień","Październik","Listopad","Grudzień"],monthsShort:["Sty.","Lut.","Mar.","Kwi.","Maj","Cze.","Lip.","Sie.","Wrz.","Paź.","Lis.","Gru."],today:"Dzisiaj",weekStart:1,clear:"Wyczyść",format:"dd.mm.yyyy"}}(jQuery);

View File

@@ -1 +1 @@
!function(a){a.fn.datepicker.dates.ro={days:["Duminică","Luni","Marţi","Miercuri","Joi","Vineri","Sâmbătă"],daysShort:["Dum","Lun","Mar","Mie","Joi","Vin","Sâm"],daysMin:["Du","Lu","Ma","Mi","Jo","Vi","Sâ"],months:["Ianuarie","Februarie","Martie","Aprilie","Mai","Iunie","Iulie","August","Septembrie","Octombrie","Noiembrie","Decembrie"],monthsShort:["Ian","Feb","Mar","Apr","Mai","Iun","Iul","Aug","Sep","Oct","Nov","Dec"],today:"Astăzi",clear:"Șterge",weekStart:1}}(jQuery);
!function(a){a.fn.datepicker.dates.ro={days:["Duminică","Luni","Marţi","Miercuri","Joi","Vineri","Sâmbătă"],daysShort:["Dum","Lun","Mar","Mie","Joi","Vin","Sâm"],daysMin:["Du","Lu","Ma","Mi","Jo","Vi","Sâ"],months:["Ianuarie","Februarie","Martie","Aprilie","Mai","Iunie","Iulie","August","Septembrie","Octombrie","Noiembrie","Decembrie"],monthsShort:["Ian","Feb","Mar","Apr","Mai","Iun","Iul","Aug","Sep","Oct","Nov","Dec"],today:"Astăzi",clear:"Șterge",weekStart:1,format:"dd/mm/yyyy"}}(jQuery);

View File

@@ -1 +1 @@
!function(a){a.fn.datepicker.dates["rs-latin"]={days:["Nedelja","Ponedeljak","Utorak","Sreda","Četvrtak","Petak","Subota"],daysShort:["Ned","Pon","Uto","Sre","Čet","Pet","Sub"],daysMin:["N","Po","U","Sr","Č","Pe","Su"],months:["Januar","Februar","Mart","April","Maj","Jun","Jul","Avgust","Septembar","Oktobar","Novembar","Decembar"],monthsShort:["Jan","Feb","Mar","Apr","Maj","Jun","Jul","Avg","Sep","Okt","Nov","Dec"],today:"Danas",weekStart:1,format:"dd.mm.yyyy"}}(jQuery);
!function(a){a.fn.datepicker.dates["rs-latin"]={days:["Nedelja","Ponedeljak","Utorak","Sreda","Četvrtak","Petak","Subota"],daysShort:["Ned","Pon","Uto","Sre","Čet","Pet","Sub"],daysMin:["N","Po","U","Sr","Č","Pe","Su"],months:["Januar","Februar","Mart","April","Maj","Jun","Jul","Avgust","Septembar","Oktobar","Novembar","Decembar"],monthsShort:["Jan","Feb","Mar","Apr","Maj","Jun","Jul","Avg","Sep","Okt","Nov","Dec"],today:"Danas",weekStart:1,format:"dd.mm.yyyy"},a.fn.datepicker.deprecated('This language code "rs-latin" is deprecated (invalid serbian language code) and will be removed in 2.0. For Serbian latin support use "sr-latin" instead.')}(jQuery);

View File

@@ -1 +1 @@
!function(a){a.fn.datepicker.dates.rs={days:["Недеља","Понедељак","Уторак","Среда","Четвртак","Петак","Субота"],daysShort:["Нед","Пон","Уто","Сре","Чет","Пет","Суб"],daysMin:["Н","По","У","Ср","Ч","Пе","Су"],months:["Јануар","Фебруар","Март","Април","Мај","Јун","Јул","Август","Септембар","Октобар","Новембар","Децембар"],monthsShort:["Јан","Феб","Мар","Апр","Мај","Јун","Јул","Авг","Сеп","Окт","Нов","Дец"],today:"Данас",weekStart:1,format:"dd.mm.yyyy"}}(jQuery);
!function(a){a.fn.datepicker.dates.rs={days:["Недеља","Понедељак","Уторак","Среда","Четвртак","Петак","Субота"],daysShort:["Нед","Пон","Уто","Сре","Чет","Пет","Суб"],daysMin:["Н","По","У","Ср","Ч","Пе","Су"],months:["Јануар","Фебруар","Март","Април","Мај","Јун","Јул","Август","Септембар","Октобар","Новембар","Децембар"],monthsShort:["Јан","Феб","Мар","Апр","Мај","Јун","Јул","Авг","Сеп","Окт","Нов","Дец"],today:"Данас",weekStart:1,format:"dd.mm.yyyy"},a.fn.datepicker.deprecated('This language code "rs" is deprecated (invalid serbian language code) and will be removed in 2.0. For Serbian support use "sr" instead.')}(jQuery);

View File

@@ -1 +1 @@
!function(a){a.fn.datepicker.dates.ru={days:["Воскресенье","Понедельник","Вторник","Среда","Четверг","Пятница","Суббота"],daysShort:["Вск","Пнд","Втр","Срд","Чтв","Птн","Суб"],daysMin:["Вс","Пн","Вт","Ср","Чт","Пт","Сб"],months:["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"],monthsShort:["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек"],today:"Сегодня",clear:"Очистить",format:"dd.mm.yyyy",weekStart:1}}(jQuery);
!function(a){a.fn.datepicker.dates.ru={days:["Воскресенье","Понедельник","Вторник","Среда","Четверг","Пятница","Суббота"],daysShort:["Вск","Пнд","Втр","Срд","Чтв","Птн","Суб"],daysMin:["Вс","Пн","Вт","Ср","Чт","Пт","Сб"],months:["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"],monthsShort:["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек"],today:"Сегодня",clear:"Очистить",format:"dd.mm.yyyy",weekStart:1,monthsTitle:"Месяцы"}}(jQuery);

View File

@@ -0,0 +1 @@
!function(a){a.fn.datepicker.dates.si={days:["ඉරිදා","සඳුදා","අඟහරුවාදා","බදාදා","බ්‍රහස්පතින්දා","සිකුරාදා","සෙනසුරාදා"],daysShort:["ඉරි","සඳු","අඟ","බදා","බ්‍රහ","සිකු","සෙන"],daysMin:["ඉ","ස","අ","බ","බ්‍ර","සි","සෙ"],months:["ජනවාරි","පෙබරවාරි","මාර්තු","අප්‍රේල්","මැයි","ජුනි","ජූලි","අගෝස්තු","සැප්තැම්බර්","ඔක්තෝබර්","නොවැම්බර්","දෙසැම්බර්"],monthsShort:["ජන","පෙබ","මාර්","අප්‍රේ","මැයි","ජුනි","ජූලි","අගෝ","සැප්","ඔක්","නොවැ","දෙසැ"],today:"අද",monthsTitle:"මාස",clear:"මකන්න",weekStart:0,format:"yyyy-mm-dd"}}(jQuery);

View File

@@ -1 +1 @@
!function(a){a.fn.datepicker.dates.sl={days:["Nedelja","Ponedeljek","Torek","Sreda","Četrtek","Petek","Sobota"],daysShort:["Ned","Pon","Tor","Sre","Čet","Pet","Sob"],daysMin:["Ne","Po","To","Sr","Če","Pe","So"],months:["Januar","Februar","Marec","April","Maj","Junij","Julij","Avgust","September","Oktober","November","December"],monthsShort:["Jan","Feb","Mar","Apr","Maj","Jun","Jul","Avg","Sep","Okt","Nov","Dec"],today:"Danes"}}(jQuery);
!function(a){a.fn.datepicker.dates.sl={days:["Nedelja","Ponedeljek","Torek","Sreda","Četrtek","Petek","Sobota"],daysShort:["Ned","Pon","Tor","Sre","Čet","Pet","Sob"],daysMin:["Ne","Po","To","Sr","Če","Pe","So"],months:["Januar","Februar","Marec","April","Maj","Junij","Julij","Avgust","September","Oktober","November","December"],monthsShort:["Jan","Feb","Mar","Apr","Maj","Jun","Jul","Avg","Sep","Okt","Nov","Dec"],today:"Danes",weekStart:1}}(jQuery);

View File

@@ -1 +1 @@
!function(a){a.fn.datepicker.dates.sq={days:["E Diel","E Hënë","E Martē","E Mërkurë","E Enjte","E Premte","E Shtunë"],daysShort:["Die","Hën","Mar","Mër","Enj","Pre","Shtu"],daysMin:["Di","Hë","Ma","Më","En","Pr","Sht"],months:["Janar","Shkurt","Mars","Prill","Maj","Qershor","Korrik","Gusht","Shtator","Tetor","Nëntor","Dhjetor"],monthsShort:["Jan","Shk","Mar","Pri","Maj","Qer","Korr","Gu","Sht","Tet","Nën","Dhjet"],today:"Sot"}}(jQuery);
!function(a){a.fn.datepicker.dates.sq={days:["E Diel","E Hënë","E Martē","E Mërkurë","E Enjte","E Premte","E Shtunë"],daysShort:["Die","Hën","Mar","Mër","Enj","Pre","Shtu"],daysMin:["Di","Hë","Ma","Më","En","Pr","Sht"],months:["Janar","Shkurt","Mars","Prill","Maj","Qershor","Korrik","Gusht","Shtator","Tetor","Nëntor","Dhjetor"],monthsShort:["Jan","Shk","Mar","Pri","Maj","Qer","Korr","Gu","Sht","Tet","Nën","Dhjet"],monthsTitle:"Muaj",today:"Sot",weekStart:1,format:"dd/mm/yyyy",clear:"Pastro"}}(jQuery);

View File

@@ -1 +1 @@
!function(a){a.fn.datepicker.dates.sv={days:["Söndag","Måndag","Tisdag","Onsdag","Torsdag","Fredag","Lördag"],daysShort:["Sön","Mån","Tis","Ons","Tor","Fre","Lör"],daysMin:["Sö","Må","Ti","On","To","Fr","Lö"],months:["Januari","Februari","Mars","April","Maj","Juni","Juli","Augusti","September","Oktober","November","December"],monthsShort:["Jan","Feb","Mar","Apr","Maj","Jun","Jul","Aug","Sep","Okt","Nov","Dec"],today:"Idag",format:"yyyy-mm-dd",weekStart:1,clear:"Rensa"}}(jQuery);
!function(a){a.fn.datepicker.dates.sv={days:["söndag","måndag","tisdag","onsdag","torsdag","fredag","lördag"],daysShort:["sön","mån","tis","ons","tor","fre","lör"],daysMin:["sö","må","ti","on","to","fr","lö"],months:["januari","februari","mars","april","maj","juni","juli","augusti","september","oktober","november","december"],monthsShort:["jan","feb","mar","apr","maj","jun","jul","aug","sep","okt","nov","dec"],today:"Idag",format:"yyyy-mm-dd",weekStart:1,clear:"Rensa"}}(jQuery);

View File

@@ -0,0 +1 @@
!function(a){a.fn.datepicker.dates.ta={days:["ஞாயிறு","திங்கள்","செவ்வாய்","புதன்","வியாழன்","வெள்ளி","சனி"],daysShort:["ஞாயி","திங்","செவ்","புத","வியா","வெள்","சனி"],daysMin:["ஞா","தி","செ","பு","வி","வெ","ச"],months:["ஜனவரி","பிப்ரவரி","மார்ச்","ஏப்ரல்","மே","ஜூன்","ஜூலை","ஆகஸ்டு","செப்டம்பர்","அக்டோபர்","நவம்பர்","டிசம்பர்"],monthsShort:["ஜன","பிப்","மார்","ஏப்","மே","ஜூன்","ஜூலை","ஆக","செப்","அக்","நவ","டிச"],today:"இன்று",monthsTitle:"மாதங்கள்",clear:"நீக்கு",weekStart:1,format:"dd/mm/yyyy"}}(jQuery);

View File

@@ -0,0 +1 @@
!function(a){a.fn.datepicker.dates.tg={days:["Якшанбе","Душанбе","Сешанбе","Чоршанбе","Панҷшанбе","Ҷумъа","Шанбе"],daysShort:["Яшб","Дшб","Сшб","Чшб","Пшб","Ҷум","Шнб"],daysMin:["Яш","Дш","Сш","Чш","Пш","Ҷм","Шб"],months:["Январ","Феврал","Март","Апрел","Май","Июн","Июл","Август","Сентябр","Октябр","Ноябр","Декабр"],monthsShort:["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек"],today:"Имрӯз",monthsTitle:"Моҳҳо",clear:"Тоза намудан",weekStart:1,format:"dd.mm.yyyy"}}(jQuery);

View File

@@ -0,0 +1 @@
!function(a){a.fn.datepicker.dates.tk={days:["Ýekşenbe","Duşenbe","Sişenbe","Çarşenbe","Penşenbe","Anna","Şenbe"],daysShort:["Ýek","Duş","Siş","Çar","Pen","Ann","Şen"],daysMin:["Ýe","Du","Si","Ça","Pe","An","Şe"],months:["Ýanwar","Fewral","Mart","Aprel","Maý","Iýun","Iýul","Awgust","Sentýabr","Oktýabr","Noýabr","Dekabr"],monthsShort:["Ýan","Few","Mar","Apr","Maý","Iýn","Iýl","Awg","Sen","Okt","Noý","Dek"],today:"Bu gün",monthsTitle:"Aýlar",clear:"Aýyr",weekStart:1,format:"dd.mm.yyyy"}}(jQuery);

View File

@@ -0,0 +1 @@
!function(a){a.fn.datepicker.dates["uz-cyrl"]={days:["Якшанба","Душанба","Сешанба","Чоршанба","Пайшанба","Жума","Шанба"],daysShort:["Якш","Ду","Се","Чор","Пай","Жу","Ша"],daysMin:["Як","Ду","Се","Чо","Па","Жу","Ша"],months:["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"],monthsShort:["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек"],today:"Бугун",clear:"Ўчириш",format:"dd.mm.yyyy",weekStart:1,monthsTitle:"Ойлар"}}(jQuery);

View File

@@ -0,0 +1 @@
!function(a){a.fn.datepicker.dates["uz-latn"]={days:["Yakshanba","Dushanba","Seshanba","Chorshanba","Payshanba","Juma","Shanba"],daysShort:["Yak","Du","Se","Chor","Pay","Ju","Sha"],daysMin:["Ya","Du","Se","Cho","Pa","Ju","Sha"],months:["Yanvar","Fevral","Mart","Aprel","May","Iyun","Iyul","Avgust","Sentabr","Oktabr","Noyabr","Dekabr"],monthsShort:["Yan","Fev","Mar","Apr","May","Iyn","Iyl","Avg","Sen","Okt","Noy","Dek"],today:"Bugun",clear:"O'chirish",format:"dd.mm.yyyy",weekStart:1,monthsTitle:"Oylar"}}(jQuery);

View File

@@ -1 +1 @@
!function(a){a.fn.datepicker.dates["zh-CN"]={days:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],daysShort:["周日","周一","周二","周三","周四","周五","周六"],daysMin:["日","一","二","三","四","五","六"],months:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],monthsShort:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],today:"今",clear:"清除",format:"yyyymmdd",titleFormat:"yyyy年mm月",weekStart:1}}(jQuery);
!function(a){a.fn.datepicker.dates["zh-CN"]={days:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],daysShort:["周日","周一","周二","周三","周四","周五","周六"],daysMin:["日","一","二","三","四","五","六"],months:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],monthsShort:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],today:"今天",monthsTitle:"选择月份",clear:"清除",format:"yyyy-mm-dd",titleFormat:"yyyy年mm月",weekStart:1}}(jQuery);

View File

@@ -0,0 +1,92 @@
// Datepicker .scss buildfile. Includes select mixins/variables from bootstrap
// and imports the included datepicker.scss to output a minimal datepicker.css
//
// Usage:
// lessc build3.scss datepicker.css
//
// Variables and mixins copied from Bootstrap 3.3.5
// These are BS3 variables that are used in datepicker3.scss. So, when compiling against
// a BS3 bootstraplib theme, these variables should already be defined. Here we set
// *defaults* for these variables based on BS4 variables, so this scss can work for
// both BS3 and BS4
$gray: mix($body-bg, $body-color, 33.5%) !default;
$gray-light: mix($body-bg, $body-color, 46.7%) !default;
$gray-lighter: mix($body-bg, $body-color, 90%) !default;
$brand-primary: $primary !default;
$btn-primary-color: $body-bg !default;
$btn-primary-bg: $primary !default;
$btn-primary-border: mix($body-color, $btn-primary-bg, 5%) !default;
$state-info-bg: mix($body-bg, $info, 80%) !default;
$border-radius-base: $border-radius !default;
$dropdown-border: $dropdown-border-color !default;
// These variables are also used in datepicker3.scss, but we don't need to set them since
// they're the same in BS3 and BS4
//$line-height-base: 1.428571429;
//$btn-link-disabled-color: $gray-light;
//$dropdown-bg: #fff;
// Setup BS4 style color contrasting
$yiq-contrasted-threshold: 150 !default;
$yiq-text-dark: #212529 !default;
$yiq-text-light: #fff !default;
@function color-yiq($color, $dark: $yiq-text-dark, $light: $yiq-text-light) {
$r: red($color);
$g: green($color);
$b: blue($color);
$yiq: (($r * 299) + ($g * 587) + ($b * 114)) / 1000;
@if ($yiq >= $yiq-contrasted-threshold) {
@return $dark;
} @else {
@return $light;
}
}
@mixin button-variant($background, $border) {
$color: color-yiq($background);
color: $color;
background-color: $background;
border-color: $border;
&:focus,
&.focus {
color: $color;
background-color: mix($background, $color, 90%);
border-color: mix($border, $color, 75%);
}
&:hover {
color: $color;
background-color: mix($background, $color, 50%);
border-color: mix($border, $color, 88%);
}
&:active,
&.active {
color: $color;
background-color: mix($background, $color, 90%);
border-color: mix($border, $color, 88%);
&:hover,
&:focus,
&.focus {
color: $color;
background-color: mix($background, $color, 83%);
border-color: mix($border, $color, 75%);
}
}
&.disabled,
&[disabled],
fieldset[disabled] & {
&:hover,
&:focus,
&.focus {
background-color: $background;
border-color: $border;
}
}
}
@import "datepicker3.scss";

View File

@@ -0,0 +1,260 @@
.datepicker {
border-radius: $border-radius-base;
&-inline {
width: 220px;
}
direction: ltr;
&-rtl {
direction: rtl;
&.dropdown-menu { left: auto; }
table tr td span {
float: right;
}
}
&-dropdown {
top: 0;
left: 0;
padding: 4px;
&:before {
content: '';
display: inline-block;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-bottom: 7px solid $dropdown-border;
border-top: 0;
border-bottom-color: rgba(0,0,0,.2);
position: absolute;
}
&:after {
content: '';
display: inline-block;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 6px solid $dropdown-bg;
border-top: 0;
position: absolute;
}
&.datepicker-orient-left:before { left: 6px; }
&.datepicker-orient-left:after { left: 7px; }
&.datepicker-orient-right:before { right: 6px; }
&.datepicker-orient-right:after { right: 7px; }
&.datepicker-orient-bottom:before { top: -7px; }
&.datepicker-orient-bottom:after { top: -6px; }
&.datepicker-orient-top:before {
bottom: -7px;
border-bottom: 0;
border-top: 7px solid $dropdown-border;
}
&.datepicker-orient-top:after {
bottom: -6px;
border-bottom: 0;
border-top: 6px solid $dropdown-bg;
}
}
table {
margin: 0;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
tr {
td, th {
text-align: center;
width: 30px;
height: 30px;
border-radius: 4px;
border: none;
}
}
}
// Inline display inside a table presents some problems with
// border and background colors.
.table-striped & table tr {
td, th {
background-color: transparent;
}
}
table tr td {
&.old,
&.new {
color: $btn-link-disabled-color;
}
&.day:hover,
&.focused {
color: color-yiq($gray-lighter);
background: $gray-lighter;
cursor: pointer;
}
&.disabled,
&.disabled:hover {
background: none;
color: $btn-link-disabled-color;
cursor: default;
}
&.highlighted {
$highlighted-bg: $state-info-bg;
@include button-variant($highlighted-bg, darken($highlighted-bg, 20%));
border-radius: 0;
&.focused {
background: darken($highlighted-bg, 10%);
}
&.disabled,
&.disabled:active {
background: $highlighted-bg;
color: $btn-link-disabled-color;
}
}
&.today {
$today-bg: lighten(orange, 30%);
@include button-variant($today-bg, darken($today-bg, 20%));
&.focused {
background: darken($today-bg, 10%);
}
&.disabled,
&.disabled:active {
background: $today-bg;
color: $btn-link-disabled-color;
}
}
&.range {
$range-bg: $gray-lighter;
@include button-variant($range-bg, darken($range-bg, 20%));
border-radius: 0;
&.focused {
background: darken($range-bg, 10%);
}
&.disabled,
&.disabled:active {
background: $range-bg;
color: $btn-link-disabled-color;
}
}
&.range.highlighted {
$range-highlighted-bg: mix($state-info-bg, $gray-lighter, 50%);
@include button-variant($range-highlighted-bg, darken($range-highlighted-bg, 20%));
&.focused {
background: darken($range-highlighted-bg, 10%);
}
&.disabled,
&.disabled:active {
background: $range-highlighted-bg;
color: $btn-link-disabled-color;
}
}
&.range.today {
$range-today-bg: mix(orange, $gray-lighter, 50%);
@include button-variant($range-today-bg, darken($range-today-bg, 20%));
&.disabled,
&.disabled:active {
background: $range-today-bg;
color: $btn-link-disabled-color;
}
}
&.selected,
&.selected.highlighted {
@include button-variant($gray-light, $gray);
text-shadow: 0 -1px 0 rgba(0,0,0,.25);
}
&.active,
&.active.highlighted {
@include button-variant($btn-primary-bg, $btn-primary-border);
text-shadow: 0 -1px 0 rgba(0,0,0,.25);
}
span {
display: block;
width: 23%;
height: 54px;
line-height: 54px;
float: left;
margin: 1%;
cursor: pointer;
border-radius: 4px;
&:hover,
&.focused {
color: color-yiq($gray-lighter);
background: $gray-lighter;
}
&.disabled,
&.disabled:hover {
background: none;
color: $btn-link-disabled-color;
cursor: default;
}
&.active,
&.active:hover,
&.active.disabled,
&.active.disabled:hover {
@include button-variant($btn-primary-bg, $btn-primary-border);
text-shadow: 0 -1px 0 rgba(0,0,0,.25);
}
&.old,
&.new {
color: $btn-link-disabled-color;
}
}
}
.datepicker-switch {
width: 145px;
}
.datepicker-switch,
.prev,
.next,
tfoot tr th {
cursor: pointer;
&:hover {
color: color-yiq($gray-lighter);
background: $gray-lighter;
}
}
.prev, .next {
&.disabled {
visibility: hidden;
}
}
// Basic styling for calendar-week cells
.cw {
font-size: 10px;
width: 12px;
padding: 0 2px 0 5px;
vertical-align: middle;
}
}
.input-group.date .input-group-addon {
cursor: pointer;
}
.input-daterange {
width: 100%;
input {
text-align: center;
}
input:first-child {
border-radius: 3px 0 0 3px;
}
input:last-child {
border-radius: 0 3px 3px 0;
}
.input-group-addon {
width: auto;
min-width: 16px;
padding: 4px 5px;
line-height: $line-height-base;
border-width: 1px 0;
margin-left: -5px;
margin-right: -5px;
}
}

View File

@@ -1,150 +1,264 @@
/* Ion.RangeSlider
// css version 2.0.3
// © 2013-2014 Denis Ineshin | IonDen.com
// ===================================================================================================================*/
/* =====================================================================================================================
// RangeSlider */
@charset "UTF-8";
/* 'shiny' skin for Ion.RangeSlider, largely based on the 'big' skin, but with smaller dimensions, grayscale grid text, and without gradients
© RStudio, Inc, 2014
© Denis Ineshin, 2014 https://github.com/IonDen
© guybowden, 2014 https://github.com/guybowden
*/
.irs {
position: relative; display: block;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
position: relative;
display: block;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
font-size: 12px;
font-family: Arial, sans-serif;
}
.irs-line {
position: relative; display: block;
overflow: hidden;
outline: none !important;
}
.irs-line-left, .irs-line-mid, .irs-line-right {
position: absolute; display: block;
top: 0;
}
.irs-line-left {
left: 0; width: 11%;
}
.irs-line-mid {
left: 9%; width: 82%;
}
.irs-line-right {
right: 0; width: 11%;
}
.irs-bar {
position: absolute; display: block;
left: 0; width: 0;
}
.irs-bar-edge {
position: absolute; display: block;
top: 0; left: 0;
}
.irs-line {
position: relative;
display: block;
overflow: hidden;
outline: none !important;
}
.irs-shadow {
position: absolute; display: none;
left: 0; width: 0;
}
.irs-bar {
position: absolute;
display: block;
left: 0;
width: 0;
}
.irs-slider {
position: absolute; display: block;
cursor: default;
z-index: 1;
}
.irs-slider.single {
.irs-shadow {
position: absolute;
display: none;
left: 0;
width: 0;
}
}
.irs-slider.from {
.irs-handle {
position: absolute;
display: block;
box-sizing: border-box;
cursor: pointer;
z-index: 1;
}
}
.irs-slider.to {
.irs-handle.type_last {
z-index: 2;
}
}
.irs-slider.type_last {
z-index: 2;
}
.irs-min, .irs-max {
position: absolute;
display: block;
cursor: default;
}
.irs-min {
position: absolute; display: block;
left: 0;
cursor: default;
}
.irs-max {
position: absolute; display: block;
right: 0;
cursor: default;
}
.irs-min {
left: 0;
}
.irs-from, .irs-to, .irs-single {
position: absolute; display: block;
top: 0; left: 0;
cursor: default;
white-space: nowrap;
}
.irs-max {
right: 0;
}
.irs-from, .irs-to, .irs-single {
position: absolute;
display: block;
top: 0;
left: 0;
cursor: default;
white-space: nowrap;
}
.irs-grid {
position: absolute; display: none;
bottom: 0; left: 0;
width: 100%; height: 20px;
position: absolute;
display: none;
bottom: 0;
left: 0;
width: 100%;
height: 20px;
}
.irs-with-grid .irs-grid {
display: block;
display: block;
}
.irs-grid-pol {
position: absolute;
top: 0;
left: 0;
width: 1px;
height: 8px;
background: #000;
}
.irs-grid-pol.small {
height: 4px;
}
.irs-grid-text {
position: absolute;
bottom: 0;
left: 0;
white-space: nowrap;
text-align: center;
font-size: 9px;
line-height: 9px;
padding: 0 3px;
color: #000;
}
.irs-grid-pol {
position: absolute;
top: 0; left: 0;
width: 1px; height: 8px;
background: #000;
}
.irs-grid-pol.small {
height: 4px;
}
.irs-grid-text {
position: absolute;
bottom: 0; left: 0;
white-space: nowrap;
text-align: center;
font-size: 9px; line-height: 9px;
padding: 0 3px;
color: #000;
}
.irs-disable-mask {
position: absolute; display: block;
top: 0; left: -1%;
width: 102%; height: 100%;
cursor: default;
background: rgba(0,0,0,0.0);
z-index: 2;
position: absolute;
display: block;
top: 0;
left: -1%;
width: 102%;
height: 100%;
cursor: default;
background: rgba(0, 0, 0, 0);
z-index: 2;
}
.lt-ie9 .irs-disable-mask {
background: #000;
filter: alpha(opacity=0);
cursor: not-allowed;
background: #000;
filter: alpha(opacity=0);
cursor: not-allowed;
}
.irs-disabled {
opacity: 0.4;
opacity: 0.4;
}
.irs-hidden-input {
position: absolute !important;
display: block !important;
top: 0 !important;
left: 0 !important;
width: 0 !important;
height: 0 !important;
font-size: 0 !important;
line-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden;
outline: none !important;
z-index: -9999 !important;
background: none !important;
border-style: solid !important;
border-color: transparent !important;
position: absolute !important;
display: block !important;
top: 0 !important;
left: 0 !important;
width: 0 !important;
height: 0 !important;
font-size: 0 !important;
line-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden;
outline: none !important;
z-index: -9999 !important;
background: none !important;
border-style: solid !important;
border-color: transparent !important;
}
.irs {
font-family: Arial, sans-serif;
}
.irs--shiny {
height: 40px;
}
.irs--shiny.irs-with-grid {
height: 60px;
}
.irs--shiny .irs-line {
top: 25px;
height: 8px;
background: linear-gradient(to bottom, #dedede -50%, white 150%);
background-color: #ededed;
border: 1px solid #cccccc;
border-radius: 8px;
}
.irs--shiny .irs-bar {
top: 25px;
height: 8px;
border-top: 1px solid #428bca;
border-bottom: 1px solid #428bca;
background: #428bca;
}
.irs--shiny .irs-bar--single {
border-radius: 8px 0 0 8px;
}
.irs--shiny .irs-shadow {
top: 38px;
height: 2px;
background: rgba(0, 0, 0, 0.3);
border-radius: 5px;
}
.irs--shiny .lt-ie9 .irs-shadow {
filter: alpha(opacity=30);
}
.irs--shiny .irs-handle {
top: 17px;
width: 22px;
height: 22px;
border: 1px solid #ababab;
background-color: #dedede;
box-shadow: 1px 1px 3px rgba(255, 255, 255, 0.3);
border-radius: 22px;
}
.irs--shiny .irs-handle.state_hover, .irs--shiny .irs-handle:hover {
background: white;
}
.irs--shiny .irs-min,
.irs--shiny .irs-max {
top: 0;
padding: 1px 3px;
color: #333333;
text-shadow: none;
background-color: rgba(0, 0, 0, 0.1);
border-radius: 3px;
font-size: 10px;
line-height: 1.333;
}
.irs--shiny .lt-ie9 .irs-min,
.irs--shiny .lt-ie9 .irs-max {
background: #cccccc;
}
.irs--shiny .irs-from,
.irs--shiny .irs-to,
.irs--shiny .irs-single {
color: #fff;
text-shadow: none;
padding: 1px 3px;
background-color: #428bca;
border-radius: 3px;
font-size: 11px;
line-height: 1.333;
}
.irs--shiny .lt-ie9 .irs-from,
.irs--shiny .lt-ie9 .irs-to,
.irs--shiny .lt-ie9 .irs-single {
background: #999999;
}
.irs--shiny .irs-grid {
height: 27px;
}
.irs--shiny .irs-grid-pol {
background-color: black;
}
.irs--shiny .irs-grid-text {
bottom: 5px;
color: #1a1a1a;
}
.irs--shiny .irs-grid-pol.small {
background-color: #999999;
}

View File

@@ -1,106 +0,0 @@
/* Ion.RangeSlider, Flat UI Skin
// css version 2.0.3
// © Denis Ineshin, 2014 https://github.com/IonDen
// ===================================================================================================================*/
/* =====================================================================================================================
// Skin details */
.irs-line-mid,
.irs-line-left,
.irs-line-right,
.irs-bar,
.irs-bar-edge,
.irs-slider {
background: url(../img/sprite-skin-flat.png) repeat-x;
}
.irs {
height: 40px;
}
.irs-with-grid {
height: 60px;
}
.irs-line {
height: 12px; top: 25px;
}
.irs-line-left {
height: 12px;
background-position: 0 -30px;
}
.irs-line-mid {
height: 12px;
background-position: 0 0;
}
.irs-line-right {
height: 12px;
background-position: 100% -30px;
}
.irs-bar {
height: 12px; top: 25px;
background-position: 0 -60px;
}
.irs-bar-edge {
top: 25px;
height: 12px; width: 9px;
background-position: 0 -90px;
}
.irs-shadow {
height: 3px; top: 34px;
background: #000;
opacity: 0.25;
}
.lt-ie9 .irs-shadow {
filter: alpha(opacity=25);
}
.irs-slider {
width: 16px; height: 18px;
top: 22px;
background-position: 0 -120px;
}
.irs-slider.state_hover, .irs-slider:hover {
background-position: 0 -150px;
}
.irs-min, .irs-max {
color: #999;
font-size: 10px; line-height: 1.333;
text-shadow: none;
top: 0; padding: 1px 3px;
background: #e1e4e9;
-moz-border-radius: 4px;
border-radius: 4px;
}
.irs-from, .irs-to, .irs-single {
color: #fff;
font-size: 10px; line-height: 1.333;
text-shadow: none;
padding: 1px 5px;
background: #ed5565;
-moz-border-radius: 4px;
border-radius: 4px;
}
.irs-from:after, .irs-to:after, .irs-single:after {
position: absolute; display: block; content: "";
bottom: -6px; left: 50%;
width: 0; height: 0;
margin-left: -3px;
overflow: hidden;
border: 3px solid transparent;
border-top-color: #ed5565;
}
.irs-grid-pol {
background: #e1e4e9;
}
.irs-grid-text {
color: #999;
}
.irs-disabled {
}

View File

@@ -1,124 +0,0 @@
/* Ion.RangeSlider, Simple Skin
// css version 2.0.3
// © Denis Ineshin, 2014 https://github.com/IonDen
// © guybowden, 2014 https://github.com/guybowden
// ===================================================================================================================*/
/* =====================================================================================================================
// Skin details */
.irs {
height: 55px;
}
.irs-with-grid {
height: 75px;
}
.irs-line {
height: 10px; top: 33px;
background: #EEE;
background: linear-gradient(to bottom, #DDD -50%, #FFF 150%); /* W3C */
border: 1px solid #CCC;
border-radius: 16px;
-moz-border-radius: 16px;
}
.irs-line-left {
height: 8px;
}
.irs-line-mid {
height: 8px;
}
.irs-line-right {
height: 8px;
}
.irs-bar {
height: 10px; top: 33px;
border-top: 1px solid #428bca;
border-bottom: 1px solid #428bca;
background: #428bca;
background: linear-gradient(to top, rgba(66,139,202,1) 0%,rgba(127,195,232,1) 100%); /* W3C */
}
.irs-bar-edge {
height: 10px; top: 33px;
width: 14px;
border: 1px solid #428bca;
border-right: 0;
background: #428bca;
background: linear-gradient(to top, rgba(66,139,202,1) 0%,rgba(127,195,232,1) 100%); /* W3C */
border-radius: 16px 0 0 16px;
-moz-border-radius: 16px 0 0 16px;
}
.irs-shadow {
height: 2px; top: 38px;
background: #000;
opacity: 0.3;
border-radius: 5px;
-moz-border-radius: 5px;
}
.lt-ie9 .irs-shadow {
filter: alpha(opacity=30);
}
.irs-slider {
top: 25px;
width: 27px; height: 27px;
border: 1px solid #AAA;
background: #DDD;
background: linear-gradient(to bottom, rgba(255,255,255,1) 0%,rgba(220,220,220,1) 20%,rgba(255,255,255,1) 100%); /* W3C */
border-radius: 27px;
-moz-border-radius: 27px;
box-shadow: 1px 1px 3px rgba(0,0,0,0.3);
cursor: pointer;
}
.irs-slider.state_hover, .irs-slider:hover {
background: #FFF;
}
.irs-min, .irs-max {
color: #333;
font-size: 12px; line-height: 1.333;
text-shadow: none;
top: 0;
padding: 1px 5px;
background: rgba(0,0,0,0.1);
border-radius: 3px;
-moz-border-radius: 3px;
}
.lt-ie9 .irs-min, .lt-ie9 .irs-max {
background: #ccc;
}
.irs-from, .irs-to, .irs-single {
color: #fff;
font-size: 14px; line-height: 1.333;
text-shadow: none;
padding: 1px 5px;
background: #428bca;
border-radius: 3px;
-moz-border-radius: 3px;
}
.lt-ie9 .irs-from, .lt-ie9 .irs-to, .lt-ie9 .irs-single {
background: #999;
}
.irs-grid {
height: 27px;
}
.irs-grid-pol {
opacity: 0.5;
background: #428bca;
}
.irs-grid-pol.small {
background: #999;
}
.irs-grid-text {
bottom: 5px;
color: #99a4ac;
}
.irs-disabled {
}

View File

@@ -1,116 +0,0 @@
/* Ion.RangeSlider, Modern Skin
// css version 2.0.3
// © Denis Ineshin, 2014 https://github.com/IonDen
// ===================================================================================================================*/
/* =====================================================================================================================
// Skin details */
.irs-line-mid,
.irs-line-left,
.irs-line-right,
.irs-bar,
.irs-bar-edge,
.irs-slider {
background: url(../img/sprite-skin-modern.png) repeat-x;
}
.irs {
height: 50px;
}
.irs-with-grid {
height: 70px;
}
.irs-line {
height: 6px; top: 25px;
}
.irs-line-left {
height: 6px;
background-position: 0 -30px;
}
.irs-line-mid {
height: 6px;
background-position: 0 0;
}
.irs-line-right {
height: 6px;
background-position: 100% -30px;
}
.irs-bar {
height: 6px; top: 25px;
background-position: 0 -60px;
}
.irs-bar-edge {
top: 25px;
height: 6px; width: 6px;
background-position: 0 -90px;
}
.irs-shadow {
height: 5px; top: 25px;
background: #000;
opacity: 0.25;
}
.lt-ie9 .irs-shadow {
filter: alpha(opacity=25);
}
.irs-slider {
width: 11px; height: 18px;
top: 31px;
background-position: 0 -120px;
}
.irs-slider.state_hover, .irs-slider:hover {
background-position: 0 -150px;
}
.irs-min, .irs-max {
color: #999;
font-size: 10px; line-height: 1.333;
text-shadow: none;
top: 0; padding: 1px 3px;
background: #e1e4e9;
-moz-border-radius: 4px;
border-radius: 4px;
}
.irs-from, .irs-to, .irs-single {
color: #fff;
font-size: 10px; line-height: 1.333;
text-shadow: none;
padding: 1px 5px;
background: #20b426;
-moz-border-radius: 4px;
border-radius: 4px;
}
.irs-from:after, .irs-to:after, .irs-single:after {
position: absolute; display: block; content: "";
bottom: -6px; left: 50%;
width: 0; height: 0;
margin-left: -3px;
overflow: hidden;
border: 3px solid transparent;
border-top-color: #20b426;
}
.irs-grid {
height: 34px;
}
.irs-grid-pol {
background: #c0c0c0;
}
.irs-grid-text {
bottom: 12px;
color: #c0c0c0;
}
.irs-disable-mask {
}
.irs-disabled {
}
.lt-ie9 .irs-disabled {
}

View File

@@ -1,102 +0,0 @@
/* Ion.RangeSlider, Nice Skin
// css version 2.0.3
// © Denis Ineshin, 2014 https://github.com/IonDen
// ===================================================================================================================*/
/* =====================================================================================================================
// Skin details */
.irs-line-mid,
.irs-line-left,
.irs-line-right,
.irs-bar,
.irs-bar-edge,
.irs-slider {
background: url(../img/sprite-skin-nice.png) repeat-x;
}
.irs {
height: 40px;
}
.irs-with-grid {
height: 60px;
}
.irs-line {
height: 8px; top: 25px;
}
.irs-line-left {
height: 8px;
background-position: 0 -30px;
}
.irs-line-mid {
height: 8px;
background-position: 0 0;
}
.irs-line-right {
height: 8px;
background-position: 100% -30px;
}
.irs-bar {
height: 8px; top: 25px;
background-position: 0 -60px;
}
.irs-bar-edge {
top: 25px;
height: 8px; width: 11px;
background-position: 0 -90px;
}
.irs-shadow {
height: 1px; top: 34px;
background: #000;
opacity: 0.15;
}
.lt-ie9 .irs-shadow {
filter: alpha(opacity=15);
}
.irs-slider {
width: 22px; height: 22px;
top: 17px;
background-position: 0 -120px;
}
.irs-slider.state_hover, .irs-slider:hover {
background-position: 0 -150px;
}
.irs-min, .irs-max {
color: #999;
font-size: 10px; line-height: 1.333;
text-shadow: none;
top: 0; padding: 1px 3px;
background: rgba(0,0,0,0.1);
-moz-border-radius: 3px;
border-radius: 3px;
}
.lt-ie9 .irs-min, .lt-ie9 .irs-max {
background: #ccc;
}
.irs-from, .irs-to, .irs-single {
color: #fff;
font-size: 10px; line-height: 1.333;
text-shadow: none;
padding: 1px 5px;
background: rgba(0,0,0,0.3);
-moz-border-radius: 3px;
border-radius: 3px;
}
.lt-ie9 .irs-from, .lt-ie9 .irs-to, .lt-ie9 .irs-single {
background: #999;
}
.irs-grid-pol {
background: #99a4ac;
}
.irs-grid-text {
color: #99a4ac;
}
.irs-disabled {
}

View File

@@ -1,108 +0,0 @@
/* Ion.RangeSlider, Round Skin
// css version 2.2.0
// © Denis Ineshin, 2014 https://github.com/IonDen
// © Veaceslav Grimalschi, 2018 https://github.com/grimalschi
// ===================================================================================================================*/
/* =====================================================================================================================
// Skin details */
.irs {
height: 50px;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.irs-with-grid {
height: 67px;
}
.irs-line {
top: 36px;
height: 4px;
background: #DEE4EC;
border-radius: 16px;
}
.irs-bar, .irs-bar-edge {
top: 36px;
height: 4px;
background: #006CFA;
}
.irs-bar-edge {
width: 12px;
}
.irs-shadow {
height: 4px;
top: 40px;
background: #DEE4EC;
opacity: 0.5;
}
.lt-ie9 .irs-shadow {
filter: alpha(opacity=25);
}
.irs-slider {
top: 35px;
width: 16px;
height: 16px;
margin-top: -10px;
border: 4px solid #006CFA;
background: white;
border-radius: 27px;
box-shadow: 0 1px 3px rgba(0,0,255,0.3);
cursor: pointer;
box-sizing: content-box;
}
.irs-slider.state_hover, .irs-slider:hover {
background: #f0f6ff;
}
.irs-min, .irs-max {
color: #333;
font-size: 14px;
top: 0;
padding: 3px 5px;
background: rgba(0,0,0,0.1);
border-radius: 3px;
line-height: 1;
}
.irs-from, .irs-to, .irs-single {
color: #fff;
font-size: 14px;
text-shadow: none;
padding: 3px 5px;
background: #006CFA;
border-radius: 3px;
line-height: 1;
}
.irs-from:after, .irs-to:after, .irs-single:after {
position: absolute;
display: block;
content: "";
bottom: -6px;
left: 50%;
width: 0;
height: 0;
margin-left: -3px;
overflow: hidden;
border: 3px solid transparent;
border-top-color: #006CFA;
}
.irs-grid {
height: 27px;
}
.irs-grid-pol {
background: #DEE4EC;
}
.irs-grid-text {
bottom: 4px;
color: silver;
font-size: 12px;
}

View File

@@ -1,128 +0,0 @@
/* Ion.RangeSlider, Shiny Skin
// This skin has been modified for use with Shiny.
// It's based on the HTML5 skin, which doesn't require any sprites, but
// has been modified to have no gradients, and to have dimensions similar to
// the skinNice theme.
// css version 2.0.0
// © RStudio, Inc, 2014
// © Denis Ineshin, 2014 https://github.com/IonDen
// © guybowden, 2014 https://github.com/guybowden
// ===================================================================================================================*/
/* =====================================================================================================================
// Skin details */
.irs {
height: 40px;
}
.irs-with-grid {
height: 60px;
}
.irs-line {
height: 8px; top: 25px;
background: #EEE;
background: linear-gradient(to bottom, #DDD -50%, #FFF 150%); /* W3C */
border: 1px solid #CCC;
border-radius: 16px;
-moz-border-radius: 16px;
}
.irs-line-left {
height: 8px;
}
.irs-line-mid {
height: 8px;
}
.irs-line-right {
height: 8px;
}
.irs-bar {
height: 8px; top: 25px;
border-top: 1px solid #428bca;
border-bottom: 1px solid #428bca;
background: #428bca;
}
.irs-bar-edge {
height: 8px; top: 25px;
width: 14px;
border: 1px solid #428bca;
border-right: 0;
background: #428bca;
border-radius: 16px 0 0 16px;
-moz-border-radius: 16px 0 0 16px;
}
.irs-shadow {
height: 2px; top: 38px;
background: #000;
opacity: 0.3;
border-radius: 5px;
-moz-border-radius: 5px;
}
.lt-ie9 .irs-shadow {
filter: alpha(opacity=30);
}
.irs-slider {
top: 17px;
width: 22px; height: 22px;
border: 1px solid #AAA;
background: #DDD;
border-radius: 27px;
-moz-border-radius: 27px;
box-shadow: 1px 1px 3px rgba(0,0,0,0.3);
cursor: pointer;
}
#irs-active-slider, .irs-slider:hover {
background: #FFF;
}
.irs-min, .irs-max {
color: #333;
font-size: 10px; line-height: 1.333;
text-shadow: none;
top: 0;
padding: 1px 3px;
background: rgba(0,0,0,0.1);
border-radius: 3px;
-moz-border-radius: 3px;
}
.lt-ie9 .irs-min, .lt-ie9 .irs-max {
background: #ccc;
}
.irs-from, .irs-to, .irs-single {
color: #fff;
font-size: 11px; line-height: 1.333;
text-shadow: none;
padding: 1px 3px;
background: #428bca;
border-radius: 3px;
-moz-border-radius: 3px;
}
.lt-ie9 .irs-from, .lt-ie9 .irs-to, .lt-ie9 .irs-single {
background: #999;
}
.irs-grid {
height: 27px;
}
.irs-grid-pol {
opacity: 0.5;
background: #428bca;
}
.irs-grid-pol.small {
background: #999;
}
.irs-grid-text {
bottom: 5px;
color: #99a4ac;
}
.irs-disabled {
}

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