Compare commits

...

32 Commits

Author SHA1 Message Date
Carson Sievert
ab219e3408 v1.11.0 release candidate (#4232) 2025-06-25 16:28:51 -05:00
Carson Sievert
673be3dd77 Follow up to #3996: fix front-end checkbox label updating logic (#4238)
* Follow up to #3996: fix front-end checkbox label updating logic

* More descriptive name
2025-06-20 15:15:30 -05:00
Carson Sievert
b25e6feabb feat(InputBinding): subscribe callback now supports event priority (#4211)
* feat(InputBinding): subscribe callback now supports event priority

* Update NEWS.md

* Update srcts/src/shiny/bind.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* `yarn build` (GitHub Actions)

* Simpler and more consistent typing

* Support a suitable object as input

* Provide a type for the callback itself, not just the valueit's given

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: cpsievert <cpsievert@users.noreply.github.com>
2025-06-19 10:27:45 -05:00
Carson Sievert
e6b22d86b6 Follow up to #3996 when label is unspecified (i.e., NULL), don't include it in the message (#4237) 2025-06-19 09:48:44 -05:00
Carson Sievert
9c5196ee63 Run routine (#4234)
* Run routine

* `devtools::document()` (GitHub Actions)

* `yarn build` (GitHub Actions)

* Update NEWS.md

---------

Co-authored-by: cpsievert <cpsievert@users.noreply.github.com>
2025-06-16 12:52:48 -05:00
Hedley
9b53251b09 chore: #4175 update jquery-ui to 1.14.1 (#4205)
* chore: #4175 update jquery-ui to 1.14.1

* Update to latest types

---------

Co-authored-by: Carson <cpsievert1@gmail.com>
2025-06-16 12:42:07 -05:00
David Macro
942bdd8c40 Update jQuery to 3.7.1 (#3969)
* Update jquery

* Upgrade to latest types

* Update news

---------

Co-authored-by: Carson Sievert <cpsievert1@gmail.com>
2025-06-16 11:46:17 -05:00
edemain03
d762865753 Fix 404 in example 08_html (shiny.min.css) (#4221)
* fix(examples-shiny): use shiny.min.css in 08_html to avoid 404 (#4220)

* Update NEWS.md

* Minimize all the files

---------

Co-authored-by: Carson Sievert <cpsievert1@gmail.com>
2025-06-16 11:20:00 -05:00
Carson Sievert
992b967095 Follow up to #3870: fix location of news item (#4233) 2025-06-16 11:12:58 -05:00
Stuart Russell
9a39cea0cc Bugfix for error found in tests (#3870)
* Bugfix for error found when calling shiny::shinyAppTemplate without library(shiny)

* Update news

* Update NEWS.md

---------

Co-authored-by: Carson <cpsievert1@gmail.com>
2025-06-16 11:05:43 -05:00
John Coene
db9f210257 Allow update input labels with HTML (#3996)
* fix: allow update input labels with HTML fixes #3995

* refactor: use processDeps and renderContent

* fix: formatting on lists

* fix: put spaces between infix

* chore: generated files

* fix: update input tests

* revert: generated javascript and sourcemaps

* fix: empty label check

* Remove package-lock

* Undo unintended change when merging

* Update news

* Simplify

---------

Co-authored-by: Carson <cpsievert1@gmail.com>
2025-06-16 11:01:44 -05:00
Charlie Gao
e8b7c08a19 Adds mirai to documentation (#4230)
* Update docs to mention mirai

* Update example to use mirai

* Fix other roxygen2 render
2025-06-16 09:42:21 -05:00
Michael Chirico
b596245571 family->given for R Core authorship (#4222) 2025-06-12 16:23:57 -05:00
Carson Sievert
57bb3a12d3 fix(renderPlot): get interactive plotting working with ggplot2 v4.0 (#4228)
* fix(renderPlot): get interactive plotting working with ggplot2 v4.0

* Update NEWS.md
2025-06-12 16:23:38 -05:00
Winston Chang
219fbc6819 Update NEWS 2025-06-09 17:22:20 -05:00
Teun van den Brand
a660093fa5 Compatibility with ggplot2 4.0.0 (#4226)
* add S7 class method

* Update tests/testthat/test-plot-coordmap.R

---------

Co-authored-by: Winston Chang <winston@stdout.org>
2025-06-09 17:20:43 -05:00
Garrick Aden-Buie
eac0eea886 fix: Wrap extended task invocation in promise_resolve() (#4225)
* fix: Wrap extended task invocation in `promise_resolve()`

* refactor: cleanup error handling and promise chain

* chore: add news entry
2025-05-30 08:44:31 -04:00
Charlie Gao
6df0bb9423 Fix performance regression related to limiting deep call stack growth (#4214)
* Use less expensive version of getCallNames() just for hashing

* Update R/conditions.R

Co-authored-by: Carson Sievert <cpsievert1@gmail.com>

---------

Co-authored-by: Carson Sievert <cpsievert1@gmail.com>
Co-authored-by: Barret Schloerke <barret@rstudio.com>
2025-05-23 18:56:00 +01:00
Barret Schloerke
159e771ac7 Relax test as we've already confirmed throttle is updating. Only required final value expectation (#4218) 2025-05-23 13:43:03 -04:00
Carson Sievert
ca41c0831b feat!(submitButton): don't treat any HTML type='submit' button/input like a submitButton() (#4209)
* feat!(submitButton): don't treat any HTML type='submit' button/input like a submitButton()

* `yarn build` (GitHub Actions)

* Sync package version (GitHub Actions)

* Update NEWS.md

* `yarn build` (GitHub Actions)

---------

Co-authored-by: cpsievert <cpsievert@users.noreply.github.com>
Co-authored-by: Barret Schloerke <barret@rstudio.com>
Co-authored-by: schloerke <schloerke@users.noreply.github.com>
2025-05-01 12:37:21 -05:00
Carson Sievert
316c3c8409 feat(textAreaInput): Add an autoresize option (#4210)
* feat(textAreaInput): Add an autoresize option

* `devtools::document()` (GitHub Actions)

* `yarn build` (GitHub Actions)

* Update NEWS.md

* Fix broken CSS selector.

Rules aren't being applied correctly in PyShiny either...

* Put shiny input class on container (to mirror what PyShiny does)

* Refactor autoresize logic

* Reduce diff size

---------

Co-authored-by: cpsievert <cpsievert@users.noreply.github.com>
2025-04-30 18:34:04 -05:00
Garrick Aden-Buie
f79a22b987 feat: Fully reload ui/server when autoreload occurs (#4184)
* feat: Fully reload ui/server when autoreload occurs

* chore: remove stray empty line

* chore: clean up function names and add comments

* docs: Add news item

* feat: Use {watcher} for autoreload file watching (#4185)

* feat: Use {watcher}

* chore: shikokuchuo/watcher@dev

* chore: watcher is on CRAN now

* chore: Undo air format changes

* feat: Use `shiny.autoreload.interval` for watcher latency

* chore: Simply track last time auto-reload changed

* docs: rewrite options docs for clarity

* chore: code style

* docs: global.R changes are not applied

* feat(ui/server): Autoreload also reloads global and R support files

* chore: remove outdated comment

* chore: safer comparisons

* chore: Restore legacy autoreload watcher if {watcher} not installed

* rename: autoload_r_support_if_needed()

* chore: use `rlang::is_false()`

* chore: use_build_ignore("_dev")
2025-04-24 13:53:40 -04:00
Garrick Aden-Buie
83219e3551 fix: Improve jquery node detection (#4203) 2025-03-25 21:26:27 -04:00
Garrick Aden-Buie
f55c26af4a docs: Link to outputOptions() from render functions (#4196)
* docs(downloadHandler): Link to `outputOptions()`

* docs: include `outputOptions()` in other render functions
2025-03-03 11:11:11 -05:00
Garrick Aden-Buie
9fbb2c5829 docs: Rewrite news for #4183 (#4195) 2025-02-28 08:06:54 -05:00
Winston Chang
531f31b66f textInput(), textAreaInput(), numericInput(), passwordInput(): allow updating value on blur (#4183)
* textInput: Add updateOn parameter and allow setting debounce delay

* `devtools::document()` (GitHub Actions)

* `yarn build` (GitHub Actions)

* Update news

* Remove debounce parameter

* `devtools::document()` (GitHub Actions)

* `yarn build` (GitHub Actions)

* Add updateOn parameter to numericInput, passwordInput

* Add updateOn to textAreaInput()

* `devtools::document()` (GitHub Actions)

* feat: Ignore change events unless from server messages when `updateOn="blur"`

* refactor: `updateOn="change"` instead of `"input"`

* feat: Update inputs on Enter or Cmd/Ctrl+Enter (textarea)

* chore: Document `...` and ensure they are empty

* chore: Use `rlang::arg_match()`

* chore: code style (air format)

* fix: textAreaInput, not inputTextArea

* docs(NEWS): Minor edit

* chore: If element has focus, ignore change event

---------

Co-authored-by: wch <wch@users.noreply.github.com>
Co-authored-by: Garrick Aden-Buie <garrick@adenbuie.com>
2025-02-26 12:45:26 -05:00
Winston Chang
58e152154a Stop using Babel; compile JS to ES2020 (#4066)
Co-authored-by: wch <wch@users.noreply.github.com>
Co-authored-by: Garrick Aden-Buie <garrick@adenbuie.com>
Co-authored-by: gadenbuie <gadenbuie@users.noreply.github.com>
Co-authored-by: Barret Schloerke <barret@posit.co>
2025-02-03 12:37:19 -05:00
Garrick Aden-Buie
55b37fdeb3 fix(insertTab): Render inserted nav html only once (#4179)
* fix: Fix checking if `scope` is a jquery element

Fixes rstudio/bslib#1159

* refactor: Don't check binding validity if `scope` isn't an element

* fix(insertTab): Render inserted nav html only once

* chore: Don't need to delay binding

* fix: Bind all after inserting nav controls

Output bindings require outputs to be attached to the DOM.

* chore: align comment

* chore: Add news item
2025-01-27 17:15:27 -05:00
Garrick Aden-Buie
b8a5aef53a feat: De-duplicate client console messages (#4177)
* feat: De-duplicate client console messages

* refactor(ShinyErrorConsole): Add `appendConsoleMessage()` static method

* fix: Make `appendConsoleMessage()` an instance method

* rename: `createClientMessageElement()`

* docs: add news item
2025-01-27 16:57:10 -05:00
Carson Sievert
d764ea9b4e Busy indicator improvements (#4172)
* Make sure spinner is visible when htmlwidget errors are visible

* Give recalculating outputs a min-height large enough to show the spinner

* tableOutput() now gets the spinner treatment

* yarn run bundle_extras

* Forward visibility hidden for all recalculating widgets, not just those with a error message (otherwise spinner won't be visible after a req())

* Update news
2025-01-22 14:14:20 -06:00
olivroy
8ad779f949 Various test lints (#4171)
Co-authored-by: Garrick Aden-Buie <garrick@adenbuie.com>
2025-01-21 15:08:00 -05:00
olivroy
7642fc84b7 Replace crayon by cli + address some TODOs to add some color (#4170)
* Replace crayon by cli + address some TODOs to add some color

* docs: add news

---------

Co-authored-by: Garrick Aden-Buie <garrick@adenbuie.com>
2025-01-21 11:00:51 -05:00
131 changed files with 8473 additions and 27501 deletions

View File

@@ -26,7 +26,6 @@
^\.vscode$
^\.madgerc$
^\.prettierrc\.yml$
^babel\.config\.json$
^jest\.config\.js$
^package\.json$
^tsconfig\.json$
@@ -37,3 +36,4 @@
^\.browserslistrc$
^\.eslintrc\.yml$
^\.yarnrc\.yml$
^_dev$

View File

@@ -1,7 +1,7 @@
Package: shiny
Type: Package
Title: Web Application Framework for R
Version: 1.10.0.9000
Version: 1.11.0
Authors@R: c(
person("Winston", "Chang", role = c("aut", "cre"), email = "winston@posit.co", comment = c(ORCID = "0000-0002-1576-2126")),
person("Joe", "Cheng", role = "aut", email = "joe@posit.co"),
@@ -60,7 +60,7 @@ Authors@R: c(
comment = "showdown.js library"),
person("Ivan", "Sagalaev", role = c("ctb", "cph"),
comment = "highlight.js library"),
person(family = "R Core Team", role = c("ctb", "cph"),
person(given = "R Core Team", role = c("ctb", "cph"),
comment = "tar implementation from R")
)
Description: Makes it incredibly easy to build interactive web
@@ -85,7 +85,7 @@ Imports:
later (>= 1.0.0),
promises (>= 1.3.2),
tools,
crayon,
cli,
rlang (>= 0.4.10),
fastmap (>= 1.1.1),
withr,
@@ -99,7 +99,7 @@ Suggests:
datasets,
DT,
Cairo (>= 1.5-5),
testthat (>= 3.0.0),
testthat (>= 3.2.1),
knitr (>= 1.6),
markdown,
rmarkdown,
@@ -107,11 +107,13 @@ Suggests:
reactlog (>= 1.0.0),
magrittr,
yaml,
mirai,
future,
dygraphs,
ragg,
showtext,
sass
sass,
watcher
URL: https://shiny.posit.co/,
https://github.com/rstudio/shiny
BugReports: https://github.com/rstudio/shiny/issues
@@ -210,7 +212,6 @@ Collate:
RoxygenNote: 7.3.2
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RdMacros: lifecycle
Config/testthat/edition: 3
Config/Needs/check:
shinytest2

52
NEWS.md
View File

@@ -1,8 +1,53 @@
# shiny (development version)
# shiny 1.11.0
## Improvements
* When auto-reload is enabled, Shiny now reloads the entire app when support files, like Shiny modules, additional script files, or web assets, change. To enable auto-reload, call `devmode(TRUE)` to enable Shiny's developer mode, or set `options(shiny.autoreload = TRUE)` to specifically enable auto-reload. You can choose which files are watched for changes with the `shiny.autoreload.pattern` option. (#4184)
* When busy indicators are enabled (i.e., `useBusyIndicators()`), Shiny now:
* Shows a spinner on recalculating htmlwidgets that have previously rendered an error (including `req()` and `validate()`). (#4172)
* Shows a spinner on `tableOutput()`. (#4172)
* Places a minimum height on recalculating outputs so that the spinner is always visible. (#4172)
* Shiny now uses `{cli}` instead of `{crayon}` for rich log messages. (thanks @olivroy, #4170)
* `renderPlot()` was updated to accommodate changes in ggplot2 v4.0.0. (#4226)
* When adding the new tab via `insertTab()` or `bslib::nav_insert()`, the underlying JavaScript no longer renders content twice. (#4179)
## New features
* `textInput()`, `textAreaInput()`, `numericInput()` and `passwordInput()` all gain an `updateOn` option. `updateOn = "change"` is the default and previous behavior, where the input value updates immediately whenever the value changes. With `updateOn = "blur"`, the input value will update only when the text input loses focus or when the user presses Enter (or Cmd/Ctrl + Enter for `textAreaInput()`). (#4183)
* `textAreaInput()` gains a `autoresize` option, which automatically resizes the text area to fit its content. (#4210)
* The family of `update*Input()` functions can now render HTML content passed to the `label` argument (e.g., `updateInputText(label = tags$b("New label"))`). (#3996)
* `ExtendedTask` now catches synchronous values and errors and returns them via `$result()`. Previously, the extended task function was required to always return a promise. This change makes it easier to use `ExtendedTask` with a function that may return early or do some synchronous work before returning a promise. (#4225)
* The `callback` argument of Shiny.js' `InputBinding.subscribe()` method gains support for a value of `"event"`. This makes it possible for an input binding to use event priority when updating the value (i.e., send immediately and always resend, even if the value hasn't changed). (#4211)
## Changes
* Shiny no longer suspends input changes when _any_ `<input type="submit">` or `<button type="submit">` is on the page. Instead, it now only suspends when a `submitButton()` is present. If you have reason for creating a submit button from custom HTML, add a CSS class of `shiny-submit-button` to the button. (#4209)
* Shiny's JavaScript assets are now compiled to ES2021 instead of ES5. (#4066)
* Upgraded jQuery from 3.6.0 to 3.7.1. (#3969)
* Updated jQuery UI from 1.13.2 to 1.14.1. (#4175)
## Bug fixes
* Fixed a bug with modals where calling `removeModal()` too quickly after `showModal()` would fail to remove the modal if the remove modal message was received while the modal was in the process of being revealed. (#4173)
* The Shiny Client Console (enabled with `shiny::devmode()`) no longer displays duplicate warning or error message. (#4177)
* Synchronous errors that occur inside a `ExtendedTask` no longer stop the session. (#4225)
* Calling `removeModal()` immediately after `showModal()` no longer fails to remove the modal (this would sometimes happen if the remove message was received while the modal was in the process of being revealed). (#4173)
* `runExample("08_html")` now (correctly) requests to 'shiny.min.css', eliminating a network request failure. (#4220)
* `shiny::shinyAppTemplate()` no longer errors without a call to `library(shiny)`. (#3870)
# shiny 1.10.0
@@ -163,7 +208,6 @@ In addition, various properties of the spinners and pulse can be customized with
* Fixed #3833: When `width` is provided to `textAreaInput()`, we now correctly set the width of the `<textarea>` element. (#3838)
# shiny 1.7.4.1
## Full changelog
@@ -352,7 +396,7 @@ This release focuses on improvements in three main areas:
* 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 #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/SalmenBejaoui/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)

View File

@@ -231,8 +231,8 @@ utils::globalVariables(".GenericCallEnv", add = TRUE)
#' promises, but rather objects provided by the
#' \href{https://rstudio.github.io/promises/}{\pkg{promises}} package, which
#' are similar to promises in JavaScript. (See [promises::promise()] for more
#' information.) You can also use [future::future()] objects to run code in a
#' separate process or even on a remote machine.
#' information.) You can also use [mirai::mirai()] or [future::future()]
#' objects to run code in a separate process or even on a remote machine.
#'
#' If the value returns a promise, then anything that consumes the cached
#' reactive must expect it to return a promise.

View File

@@ -1113,7 +1113,7 @@ plotOutput <- function(outputId, width = "100%", height="400px",
#' @rdname renderTable
#' @export
tableOutput <- function(outputId) {
div(id = outputId, class="shiny-html-output")
div(id = outputId, class="shiny-html-output shiny-table-output")
}
dataTableDependency <- list(

View File

@@ -75,6 +75,18 @@ getCallNames <- function(calls) {
})
}
# A stripped down version of getCallNames() that intentionally avoids deparsing expressions.
# Instead, it leaves expressions to be directly `rlang::hash()` (for de-duplication), which
# is much faster than deparsing then hashing.
getCallNamesForHash <- function(calls) {
lapply(calls, function(call) {
name <- call[[1L]]
if (is.function(name)) return("<Anonymous>")
if (typeof(name) == "promise") return("<Promise>")
name
})
}
getLocs <- function(calls) {
vapply(calls, function(call) {
srcref <- attr(call, "srcref", exact = TRUE)
@@ -144,7 +156,7 @@ getCallStackDigest <- function(callStack, warn = FALSE) {
)
}
rlang::hash(getCallNames(callStack))
rlang::hash(getCallNamesForHash(callStack))
}
saveCallStackDigest <- function(callStack) {
@@ -417,11 +429,11 @@ printOneStackTrace <- function(stackTrace, stripResult, full, offset) {
": ",
mapply(paste0(st$call, st$loc), st$category, FUN = function(name, category) {
if (category == "pkg")
crayon::silver(name)
cli::col_silver(name)
else if (category == "user")
crayon::blue$bold(name)
cli::style_bold(cli::col_blue(name))
else
crayon::white(name)
cli::col_white(name)
}),
"\n"
)

View File

@@ -41,12 +41,15 @@
#' is, a function that quickly returns a promise) and allows even that very
#' session to immediately unblock and carry on with other user interactions.
#'
#' @examplesIf rlang::is_interactive() && rlang::is_installed("future")
#'
#' @examplesIf rlang::is_interactive() && rlang::is_installed("mirai")
#' library(shiny)
#' library(bslib)
#' library(future)
#' plan(multisession)
#' library(mirai)
#'
#' # Set background processes for running tasks
#' daemons(1)
#' # Reset when the app is stopped
#' onStop(function() daemons(0))
#'
#' ui <- page_fluid(
#' titlePanel("Extended Task Demo"),
@@ -60,13 +63,12 @@
#'
#' server <- function(input, output) {
#' rand_task <- ExtendedTask$new(function() {
#' future(
#' mirai(
#' {
#' # Slow operation goes here
#' Sys.sleep(2)
#' sample(1:100, 1)
#' },
#' seed = TRUE
#' }
#' )
#' })
#'
@@ -100,11 +102,12 @@ ExtendedTask <- R6Class("ExtendedTask", portable = TRUE, cloneable = FALSE,
#' @param func The long-running operation to execute. This should be an
#' asynchronous function, meaning, it should use the
#' [\{promises\}](https://rstudio.github.io/promises/) package, most
#' likely in conjuction with the
#' likely in conjunction with the
#' [\{mirai\}](https://mirai.r-lib.org) or
#' [\{future\}](https://rstudio.github.io/promises/articles/promises_04_futures.html)
#' package. (In short, the return value of `func` should be a
#' [`Future`][future::future()] object, or a `promise`, or something else
#' that [promises::as.promise()] understands.)
#' [`mirai`][mirai::mirai()], [`Future`][future::future()], `promise`,
#' or something else that [promises::as.promise()] understands.)
#'
#' It's also important that this logic does not read from any
#' reactive inputs/sources, as inputs may change after the function is
@@ -130,14 +133,15 @@ ExtendedTask <- R6Class("ExtendedTask", portable = TRUE, cloneable = FALSE,
#' arguments.
invoke = function(...) {
args <- rlang::dots_list(..., .ignore_empty = "none")
call <- rlang::caller_call(n = 0)
if (
isolate(private$rv_status()) == "running" ||
private$invocation_queue$size() > 0
) {
private$invocation_queue$add(args)
private$invocation_queue$add(list(args = args, call = call))
} else {
private$do_invoke(args)
private$do_invoke(args, call = call)
}
invisible(NULL)
},
@@ -204,44 +208,41 @@ ExtendedTask <- R6Class("ExtendedTask", portable = TRUE, cloneable = FALSE,
rv_error = NULL,
invocation_queue = NULL,
do_invoke = function(args) {
do_invoke = function(args, call = NULL) {
private$rv_status("running")
private$rv_value(NULL)
private$rv_error(NULL)
p <- NULL
tryCatch({
maskReactiveContext({
# TODO: Bounce the do.call off of a promise_resolve(), so that the
# call to invoke() always returns immediately?
result <- do.call(private$func, args)
p <- promises::as.promise(result)
})
}, error = function(e) {
private$on_error(e)
})
p <- promises::promise_resolve(
maskReactiveContext(do.call(private$func, args))
)
promises::finally(
promises::then(p,
onFulfilled = function(value, .visible) {
private$on_success(list(value=value, visible=.visible))
},
onRejected = function(error) {
private$on_error(error)
}
),
onFinally = function() {
if (private$invocation_queue$size() > 0) {
private$do_invoke(private$invocation_queue$remove())
}
p <- promises::then(
p,
onFulfilled = function(value, .visible) {
private$on_success(list(value = value, visible = .visible))
},
onRejected = function(error) {
private$on_error(error, call = call)
}
)
promises::finally(p, onFinally = function() {
if (private$invocation_queue$size() > 0) {
next_call <- private$invocation_queue$remove()
private$do_invoke(next_call$args, next_call$call)
}
})
invisible(NULL)
},
on_error = function(err) {
on_error = function(err, call = NULL) {
cli::cli_warn(
"ERROR: An error occurred when invoking the ExtendedTask.",
parent = err,
call = call
)
private$rv_status("error")
private$rv_error(err)
},

View File

@@ -29,22 +29,36 @@
#' A numeric vector of length 1.
#'
#' @export
numericInput <- function(inputId, label, value, min = NA, max = NA, step = NA,
width = NULL) {
numericInput <- function(
inputId,
label,
value,
min = NA,
max = NA,
step = NA,
width = NULL,
...,
updateOn = c("change", "blur")
) {
rlang::check_dots_empty()
updateOn <- rlang::arg_match(updateOn)
value <- restoreInput(id = inputId, default = value)
# build input tag
inputTag <- tags$input(id = inputId, type = "number", class="shiny-input-number form-control",
value = formatNoSci(value))
if (!is.na(min))
inputTag$attribs$min = min
if (!is.na(max))
inputTag$attribs$max = max
if (!is.na(step))
inputTag$attribs$step = step
inputTag <- tags$input(
id = inputId,
type = "number",
class = "shiny-input-number form-control",
value = formatNoSci(value),
`data-update-on` = updateOn
)
if (!is.na(min)) inputTag$attribs$min = min
if (!is.na(max)) inputTag$attribs$max = max
if (!is.na(step)) inputTag$attribs$step = step
div(class = "form-group shiny-input-container",
div(
class = "form-group shiny-input-container",
style = css(width = validateCssUnit(width)),
shinyInputLabel(inputId, label),
inputTag

View File

@@ -30,12 +30,29 @@
#' shinyApp(ui, server)
#' }
#' @export
passwordInput <- function(inputId, label, value = "", width = NULL,
placeholder = NULL) {
div(class = "form-group shiny-input-container",
passwordInput <- function(
inputId,
label,
value = "",
width = NULL,
placeholder = NULL,
...,
updateOn = c("change", "blur")
) {
rlang::check_dots_empty()
updateOn <- rlang::arg_match(updateOn)
div(
class = "form-group shiny-input-container",
style = css(width = validateCssUnit(width)),
shinyInputLabel(inputId, label),
tags$input(id = inputId, type="password", class="shiny-input-password form-control", value=value,
placeholder = placeholder)
tags$input(
id = inputId,
type = "password",
class = "shiny-input-password form-control",
value = value,
placeholder = placeholder,
`data-update-on` = updateOn
)
)
}

View File

@@ -57,7 +57,7 @@ submitButton <- function(text = "Apply Changes", icon = NULL, width = NULL) {
div(
tags$button(
type="submit",
class="btn btn-primary",
class="btn btn-primary shiny-submit-button",
style = css(width = validateCssUnit(width)),
list(icon, text)
)

View File

@@ -10,6 +10,14 @@
#' @param placeholder A character string giving the user a hint as to what can
#' be entered into the control. Internet Explorer 8 and 9 do not support this
#' option.
#' @param ... Ignored, included to require named arguments and for future
#' feature expansion.
#' @param updateOn A character vector specifying when the input should be
#' updated. Options are `"change"` (default) and `"blur"`. Use `"change"` to
#' update the input immediately whenever the value changes. Use `"blur"`to
#' delay the input update until the input loses focus (the user moves away
#' from the input), or when Enter is pressed (or Cmd/Ctrl + Enter for
#' [textAreaInput()]).
#' @return A text input control that can be added to a UI definition.
#'
#' @family input elements
@@ -34,15 +42,31 @@
#' unless `value` is provided.
#'
#' @export
textInput <- function(inputId, label, value = "", width = NULL,
placeholder = NULL) {
textInput <- function(
inputId,
label,
value = "",
width = NULL,
placeholder = NULL,
...,
updateOn = c("change", "blur")
) {
rlang::check_dots_empty()
updateOn <- rlang::arg_match(updateOn)
value <- restoreInput(id = inputId, default = value)
div(class = "form-group shiny-input-container",
div(
class = "form-group shiny-input-container",
style = css(width = validateCssUnit(width)),
shinyInputLabel(inputId, label),
tags$input(id = inputId, type="text", class="shiny-input-text form-control", value=value,
placeholder = placeholder)
tags$input(
id = inputId,
type = "text",
class = "shiny-input-text form-control",
value = value,
placeholder = placeholder,
`data-update-on` = updateOn
)
)
}

View File

@@ -16,6 +16,8 @@
#' @param resize Which directions the textarea box can be resized. Can be one of
#' `"both"`, `"none"`, `"vertical"`, and `"horizontal"`. The default, `NULL`,
#' will use the client browser's default setting for resizing textareas.
#' @param autoresize If `TRUE`, the textarea will automatically resize to fit
#' the input text.
#' @return A textarea input control that can be added to a UI definition.
#'
#' @family input elements
@@ -41,8 +43,22 @@
#' unless `value` is provided.
#'
#' @export
textAreaInput <- function(inputId, label, value = "", width = NULL, height = NULL,
cols = NULL, rows = NULL, placeholder = NULL, resize = NULL) {
textAreaInput <- function(
inputId,
label,
value = "",
width = NULL,
height = NULL,
cols = NULL,
rows = NULL,
placeholder = NULL,
resize = NULL,
...,
autoresize = FALSE,
updateOn = c("change", "blur")
) {
rlang::check_dots_empty()
updateOn <- rlang::arg_match(updateOn)
value <- restoreInput(id = inputId, default = value)
@@ -50,23 +66,30 @@ textAreaInput <- function(inputId, label, value = "", width = NULL, height = NUL
resize <- match.arg(resize, c("both", "none", "vertical", "horizontal"))
}
style <- css(
# The width is specified on the parent div.
width = if (!is.null(width)) "100%",
height = validateCssUnit(height),
resize = resize
)
classes <- "form-control"
if (autoresize) {
classes <- c(classes, "textarea-autoresize")
if (is.null(rows)) {
rows <- 1
}
}
div(class = "form-group shiny-input-container",
div(
class = "shiny-input-textarea form-group shiny-input-container",
style = css(width = validateCssUnit(width)),
shinyInputLabel(inputId, label),
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
tags$textarea(
id = inputId,
class = "shiny-input-textarea form-control",
class = classes,
placeholder = placeholder,
style = style,
style = css(
width = if (!is.null(width)) "100%",
height = validateCssUnit(height),
resize = resize
),
rows = rows,
cols = cols,
`data-update-on` = updateOn,
value
)
)

View File

@@ -266,6 +266,8 @@ drawPlot <- function(name, session, func, width, height, alt, pixelratio, res, .
# addition to ggplot, and there's a print method for that class, that we
# won't override that method. https://github.com/rstudio/shiny/issues/841
print.ggplot <- custom_print.ggplot
# For compatibility with ggplot2 >v4.0.0
`print.ggplot2::ggplot` <- custom_print.ggplot
# Use capture.output to squelch printing to the actual console; we
# are only interested in plot output

View File

@@ -65,16 +65,20 @@ getShinyOption <- function(name, default = NULL) {
#' changes are detected, all connected Shiny sessions are reloaded. This
#' allows for fast feedback loops when tweaking Shiny UI.
#'
#' Since monitoring for changes is expensive (we simply poll for last
#' modified times), this feature is intended only for development.
#' Monitoring for changes is no longer expensive, thanks to the \pkg{watcher}
#' package, but this feature is still intended only for development.
#'
#' You can customize the file patterns Shiny will monitor by setting the
#' shiny.autoreload.pattern option. For example, to monitor only ui.R:
#' `options(shiny.autoreload.pattern = glob2rx("ui.R"))`
#' shiny.autoreload.pattern option. For example, to monitor only `ui.R`:
#' `options(shiny.autoreload.pattern = glob2rx("ui.R"))`.
#'
#' The default polling interval is 500 milliseconds. You can change this
#' by setting e.g. `options(shiny.autoreload.interval = 2000)` (every
#' two seconds).}
#' As mentioned above, Shiny no longer polls watched files for changes.
#' Instead, using \pkg{watcher}, Shiny is notified of file changes as they
#' occur. These changes are batched together within a customizable latency
#' period. You can adjust this period by setting
#' `options(shiny.autoreload.interval = 2000)` (in milliseconds). This value
#' converted to seconds and passed to the `latency` argument of
#' [watcher::watcher()]. The default latency is 250ms.}
#' \item{shiny.deprecation.messages (defaults to `TRUE`)}{This controls whether messages for
#' deprecated functions in Shiny will be printed. See
#' [shinyDeprecated()] for more information.}

View File

@@ -162,11 +162,29 @@ shinyAppDir_serverR <- function(appDir, options=list()) {
sharedEnv <- globalenv()
}
# To enable hot-reloading of support files, this function is called
# whenever the UI or Server func source is updated. To avoid loading
# support files 2x, we follow the last cache update trigger timestamp.
autoload_r_support_if_needed <- local({
autoload_last_loaded <- -1
function() {
if (!isTRUE(getOption("shiny.autoload.r", TRUE))) return()
last_cache_trigger <- cachedAutoReloadLastChanged$get()
if (identical(autoload_last_loaded, last_cache_trigger)) return()
loadSupport(appDir, renv = sharedEnv, globalrenv = globalenv())
autoload_last_loaded <<- last_cache_trigger
}
})
# uiHandlerSource is a function that returns an HTTP handler for serving up
# ui.R as a webpage. The "cachedFuncWithFile" call makes sure that the closure
# we're creating here only gets executed when ui.R's contents change.
uiHandlerSource <- cachedFuncWithFile(appDir, "ui.R", case.sensitive = FALSE,
function(uiR) {
autoload_r_support_if_needed()
if (file.exists(uiR)) {
# If ui.R contains a call to shinyUI (which sets .globals$ui), use that.
# If not, then take the last expression that's returned from ui.R.
@@ -197,6 +215,7 @@ shinyAppDir_serverR <- function(appDir, options=list()) {
serverSource <- cachedFuncWithFile(appDir, "server.R", case.sensitive = FALSE,
function(serverR) {
autoload_r_support_if_needed()
# If server.R contains a call to shinyServer (which sets .globals$server),
# use that. If not, then take the last expression that's returned from
# server.R.
@@ -232,10 +251,9 @@ shinyAppDir_serverR <- function(appDir, options=list()) {
onStart <- function() {
oldwd <<- getwd()
setwd(appDir)
# TODO: we should support hot reloading on global.R and R/*.R changes.
if (getOption("shiny.autoload.r", TRUE)) {
loadSupport(appDir, renv=sharedEnv, globalrenv=globalenv())
} else {
autoload_r_support_if_needed()
} else {
if (file.exists(file.path.ci(appDir, "global.R")))
sourceUTF8(file.path.ci(appDir, "global.R"))
}
@@ -290,33 +308,77 @@ initAutoReloadMonitor <- function(dir) {
return(function(){})
}
filePattern <- getOption("shiny.autoreload.pattern",
".*\\.(r|html?|js|css|png|jpe?g|gif)$")
filePattern <- getOption(
"shiny.autoreload.pattern",
".*\\.(r|html?|js|css|png|jpe?g|gif)$"
)
lastValue <- NULL
observeLabel <- paste0("File Auto-Reload - '", basename(dir), "'")
obs <- observe(label = observeLabel, {
files <- sort_c(
list.files(dir, pattern = filePattern, recursive = TRUE, ignore.case = TRUE)
)
times <- file.info(files)$mtime
names(times) <- files
if (is.null(lastValue)) {
# First run
lastValue <<- times
} else if (!identical(lastValue, times)) {
# We've changed!
lastValue <<- times
if (is_installed("watcher")) {
check_for_update <- function(paths) {
paths <- grep(
filePattern,
paths,
ignore.case = TRUE,
value = TRUE
)
if (length(paths) == 0) {
return()
}
cachedAutoReloadLastChanged$set()
autoReloadCallbacks$invoke()
}
# [garrick, 2025-02-20] Shiny <= v1.10.0 used `invalidateLater()` with an
# autoreload.interval in ms. {watcher} instead uses a latency parameter in
# seconds, which serves a similar purpose and that I'm keeping for backcompat.
latency <- getOption("shiny.autoreload.interval", 250) / 1000
watcher <- watcher::watcher(dir, check_for_update, latency = latency)
watcher$start()
onStop(watcher$stop)
} else {
# Fall back to legacy observer behavior
if (!is_false(getOption("shiny.autoreload.legacy_warning", TRUE))) {
cli::cli_warn(
c(
"Using legacy autoreload file watching. Please install {.pkg watcher} for a more performant autoreload file watcher.",
"i" = "Set {.run options(shiny.autoreload.legacy_warning = FALSE)} to suppress this warning."
),
.frequency = "regularly",
.frequency_id = "shiny.autoreload.legacy_warning"
)
}
invalidateLater(getOption("shiny.autoreload.interval", 500))
})
lastValue <- NULL
observeLabel <- paste0("File Auto-Reload - '", basename(dir), "'")
watcher <- observe(label = observeLabel, {
files <- sort_c(
list.files(dir, pattern = filePattern, recursive = TRUE, ignore.case = TRUE)
)
times <- file.info(files)$mtime
names(times) <- files
if (is.null(lastValue)) {
# First run
lastValue <<- times
} else if (!identical(lastValue, times)) {
# We've changed!
lastValue <<- times
cachedAutoReloadLastChanged$set()
autoReloadCallbacks$invoke()
}
invalidateLater(getOption("shiny.autoreload.interval", 500))
})
onStop(watcher$destroy)
watcher$destroy
}
onStop(obs$destroy)
obs$destroy
invisible(watcher)
}
#' Load an app's supporting R files
@@ -421,8 +483,6 @@ shinyAppDir_appR <- function(fileName, appDir, options=list())
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.

View File

@@ -383,8 +383,10 @@ markOutputAttrs <- function(renderFunc, snapshotExclude = NULL,
#' The corresponding HTML output tag should be `div` or `img` and have
#' the CSS class name `shiny-image-output`.
#'
#' @seealso For more details on how the images are generated, and how to control
#' @seealso
#' * For more details on how the images are generated, and how to control
#' the output, see [plotPNG()].
#' * Use [outputOptions()] to set general output options for an image output.
#'
#' @param expr An expression that returns a list.
#' @inheritParams renderUI
@@ -598,6 +600,7 @@ isTemp <- function(path, tempDir = tempdir(), mustExist) {
#' used in an interactive RMarkdown document.
#'
#' @example res/text-example.R
#' @seealso [outputOptions()]
#' @export
renderPrint <- function(expr, env = parent.frame(), quoted = FALSE,
width = getOption('width'), outputArgs=list())
@@ -719,7 +722,7 @@ renderText <- function(expr, env = parent.frame(), quoted = FALSE,
#' call to [uiOutput()] when `renderUI` is used in an
#' interactive R Markdown document.
#'
#' @seealso [uiOutput()]
#' @seealso [uiOutput()], [outputOptions()]
#' @export
#' @examples
#' ## Only run examples in interactive R sessions
@@ -809,6 +812,13 @@ renderUI <- function(expr, env = parent.frame(), quoted = FALSE,
#'
#' shinyApp(ui, server)
#' }
#'
#' @seealso
#' * The download handler, like other outputs, is suspended (disabled) by
#' default for download buttons and links that are hidden. Use
#' [outputOptions()] to control this behavior, e.g. to set
#' `suspendWhenHidden = FALSE` if the download is initiated by
#' programmatically clicking on the download button using JavaScript.
#' @export
downloadHandler <- function(filename, content, contentType=NULL, outputArgs=list()) {
renderFunc <- function(shinysession, name, ...) {

View File

@@ -158,8 +158,7 @@ print.shiny_runtests <- function(x, ..., reporter = "summary") {
if (any(x$pass)) {
# TODO in future... use clisymbols::symbol$tick and crayon green
cat("* Success\n")
cli::cat_bullet("Success", bullet = "tick", bullet_col = "green")
mapply(
x$file,
x$pass,
@@ -171,9 +170,8 @@ print.shiny_runtests <- function(x, ..., reporter = "summary") {
}
)
}
if (any(!x$pass)) {
# TODO in future... use clisymbols::symbol$cross and crayon red
cat("* Failure\n")
if (!all(x$pass)) {
cli::cat_bullet("Failure", bullet = "cross", bullet_col = "red")
mapply(
x$file,
x$pass,

View File

@@ -37,7 +37,11 @@
updateTextInput <- function(session = getDefaultReactiveDomain(), inputId, label = NULL, value = NULL, placeholder = NULL) {
validate_session_object(session)
message <- dropNulls(list(label=label, value=value, placeholder=placeholder))
message <- dropNulls(list(
label = if (!is.null(label)) processDeps(label, session),
value = value,
placeholder = placeholder
))
session$sendInputMessage(inputId, message)
}
@@ -111,7 +115,10 @@ updateTextAreaInput <- updateTextInput
updateCheckboxInput <- function(session = getDefaultReactiveDomain(), inputId, label = NULL, value = NULL) {
validate_session_object(session)
message <- dropNulls(list(label=label, value=value))
message <- dropNulls(list(
label = if (!is.null(label)) processDeps(label, session),
value = value
))
session$sendInputMessage(inputId, message)
}
@@ -175,13 +182,22 @@ updateActionButton <- function(session = getDefaultReactiveDomain(), inputId, la
validate_session_object(session)
if (!is.null(icon)) icon <- as.character(validateIcon(icon))
message <- dropNulls(list(label=label, icon=icon, disabled=disabled))
message <- dropNulls(list(
label = if (!is.null(label)) processDeps(label, session),
icon = icon,
disabled = disabled
))
session$sendInputMessage(inputId, message)
}
#' @rdname updateActionButton
#' @export
updateActionLink <- function(session = getDefaultReactiveDomain(), inputId, label = NULL, icon = NULL) {
updateActionButton(session, inputId=inputId, label=label, icon=icon)
updateActionButton(
session,
inputId = inputId,
label = label,
icon = icon
)
}
@@ -225,7 +241,12 @@ updateDateInput <- function(session = getDefaultReactiveDomain(), inputId, label
min <- dateYMD(min, "min")
max <- dateYMD(max, "max")
message <- dropNulls(list(label=label, value=value, min=min, max=max))
message <- dropNulls(list(
label = if (!is.null(label)) processDeps(label, session),
value = value,
min = min,
max = max
))
session$sendInputMessage(inputId, message)
}
@@ -275,7 +296,7 @@ updateDateRangeInput <- function(session = getDefaultReactiveDomain(), inputId,
max <- dateYMD(max, "max")
message <- dropNulls(list(
label = label,
label = if (!is.null(label)) processDeps(label, session),
value = dropNulls(list(start = start, end = end)),
min = min,
max = max
@@ -374,13 +395,16 @@ updateNavlistPanel <- updateTabsetPanel
#' }
#' @export
updateNumericInput <- function(session = getDefaultReactiveDomain(), inputId, label = NULL, value = NULL,
min = NULL, max = NULL, step = NULL) {
min = NULL, max = NULL, step = NULL) {
validate_session_object(session)
message <- dropNulls(list(
label = label, value = formatNoSci(value),
min = formatNoSci(min), max = formatNoSci(max), step = formatNoSci(step)
label = if (!is.null(label)) processDeps(label, session),
value = formatNoSci(value),
min = formatNoSci(min),
max = formatNoSci(max),
step = formatNoSci(step)
))
session$sendInputMessage(inputId, message)
}
@@ -460,7 +484,7 @@ updateSliderInput <- function(session = getDefaultReactiveDomain(), inputId, lab
}
message <- dropNulls(list(
label = label,
label = if (!is.null(label)) processDeps(label, session),
value = formatNoSci(value),
min = formatNoSci(min),
max = formatNoSci(max),
@@ -491,7 +515,11 @@ updateInputOptions <- function(session, inputId, label = NULL, choices = NULL,
))
}
message <- dropNulls(list(label = label, options = options, value = selected))
message <- dropNulls(list(
label = if (!is.null(label)) processDeps(label, session),
options = options,
value = selected
))
session$sendInputMessage(inputId, message)
}
@@ -644,7 +672,11 @@ updateSelectInput <- function(session = getDefaultReactiveDomain(), inputId, lab
choices <- if (!is.null(choices)) choicesWithNames(choices)
if (!is.null(selected)) selected <- as.character(selected)
options <- if (!is.null(choices)) selectOptions(choices, selected, inputId, FALSE)
message <- dropNulls(list(label = label, options = options, value = selected))
message <- dropNulls(list(
label = if (!is.null(label)) processDeps(label, session),
options = options,
value = selected
))
session$sendInputMessage(inputId, message)
}

View File

@@ -770,22 +770,45 @@ formatNoSci <- function(x) {
format(x, scientific = FALSE, digits = 15)
}
# A simple getter/setting to track the last time the auto-reload process
# updated. This value is used by `cachedFuncWithFile()` when auto-reload is
# enabled to reload app/ui/server files when watched supporting files change.
cachedAutoReloadLastChanged <- local({
last_update <- 0
list(
set = function() {
last_update <<- as.integer(Sys.time())
invisible(last_update)
},
get = function() {
last_update
}
)
})
# Returns a function that calls the given func and caches the result for
# subsequent calls, unless the given file's mtime changes.
cachedFuncWithFile <- function(dir, file, func, case.sensitive = FALSE) {
dir <- normalizePath(dir, mustWork=TRUE)
mtime <- NA
dir <- normalizePath(dir, mustWork = TRUE)
value <- NULL
last_mtime_file <- NA
last_autoreload <- 0
function(...) {
fname <- if (case.sensitive)
file.path(dir, file)
else
fname <- if (case.sensitive) {
file.path(dir, file)
} else {
file.path.ci(dir, file)
}
now <- file.info(fname)$mtime
if (!identical(mtime, now)) {
autoreload <- last_autoreload < cachedAutoReloadLastChanged$get()
if (autoreload || !identical(last_mtime_file, now)) {
value <<- func(fname, ...)
mtime <<- now
last_mtime_file <<- now
last_autoreload <<- cachedAutoReloadLastChanged$get()
}
value
}

View File

@@ -1,2 +1,2 @@
# Generated by tools/updatejQuery.R; do not edit by hand
version_jquery <- "3.6.0"
version_jquery <- "3.7.1"

View File

@@ -1,2 +1,2 @@
# Generated by tools/updatejQueryUI.R; do not edit by hand
version_jqueryui <- "1.13.2"
version_jqueryui <- "1.14.1"

View File

@@ -1,15 +0,0 @@
{
"presets": [
"@babel/preset-typescript",
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": "3.12"
}
]
],
"ignore":[
"node_modules/core-js"
]
}

View File

@@ -5,7 +5,7 @@ test_that("Initial snapshot values are consistent", {
app$expect_values()
}){{
if (isTRUE(module)) {
HTML('
shiny::HTML('
test_that("Module values are consistent", {

View File

@@ -1,9 +1,9 @@
<html>
<head>
<script src="shared/jquery.js" type="text/javascript"></script>
<script src="shared/shiny.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="shared/shiny.css"/>
<script src="shared/jquery.min.js" type="text/javascript"></script>
<script src="shared/shiny.min.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="shared/shiny.min.css"/>
</head>
<body>

View File

@@ -1,2 +1,2 @@
/*! shiny 1.10.0.9000 | (c) 2012-2025 Posit Software, PBC. | License: GPL-3 | file LICENSE */
:where([data-shiny-busy-spinners] .recalculating){position:relative}[data-shiny-busy-spinners] .recalculating:after{position:absolute;content:"";--_shiny-spinner-url: var(--shiny-spinner-url, url(spinners/ring.svg));--_shiny-spinner-color: var(--shiny-spinner-color, var(--bs-primary, #007bc2));--_shiny-spinner-size: var(--shiny-spinner-size, 32px);--_shiny-spinner-delay: var(--shiny-spinner-delay, 1s);background:var(--_shiny-spinner-color);width:var(--_shiny-spinner-size);height:var(--_shiny-spinner-size);inset:calc(50% - var(--_shiny-spinner-size) / 2);mask-image:var(--_shiny-spinner-url);-webkit-mask-image:var(--_shiny-spinner-url);opacity:0;animation-delay:var(--_shiny-spinner-delay);animation-name:fade-in;animation-duration:.25s;animation-fill-mode:forwards}[data-shiny-busy-spinners] .recalculating:has(>*),[data-shiny-busy-spinners] .recalculating:empty{opacity:1}[data-shiny-busy-spinners] .recalculating>*:not(.recalculating){opacity:var(--_shiny-fade-opacity);transition:opacity .25s ease var(--shiny-spinner-delay, 1s)}[data-shiny-busy-spinners] .recalculating.shiny-html-output:after{display:none}[data-shiny-busy-spinners][data-shiny-busy-pulse].shiny-busy:after{--_shiny-pulse-background: var( --shiny-pulse-background, linear-gradient( 120deg, transparent, var(--bs-indigo, #4b00c1), var(--bs-purple, #74149c), var(--bs-pink, #bf007f), transparent ) );--_shiny-pulse-height: var(--shiny-pulse-height, 3px);--_shiny-pulse-speed: var(--shiny-pulse-speed, 1.2s);position:fixed;top:0;left:0;height:var(--_shiny-pulse-height);background:var(--_shiny-pulse-background);z-index:9999;animation-name:busy-page-pulse;animation-duration:var(--_shiny-pulse-speed);animation-direction:alternate;animation-iteration-count:infinite;animation-timing-function:ease-in-out;content:""}[data-shiny-busy-spinners][data-shiny-busy-pulse].shiny-busy:has(.recalculating:not(.shiny-html-output)):after{display:none}[data-shiny-busy-spinners][data-shiny-busy-pulse].shiny-busy:has(#shiny-disconnected-overlay):after{display:none}[data-shiny-busy-pulse]:not([data-shiny-busy-spinners]).shiny-busy:after{--_shiny-pulse-background: var( --shiny-pulse-background, linear-gradient( 120deg, transparent, var(--bs-indigo, #4b00c1), var(--bs-purple, #74149c), var(--bs-pink, #bf007f), transparent ) );--_shiny-pulse-height: var(--shiny-pulse-height, 3px);--_shiny-pulse-speed: var(--shiny-pulse-speed, 1.2s);position:fixed;top:0;left:0;height:var(--_shiny-pulse-height);background:var(--_shiny-pulse-background);z-index:9999;animation-name:busy-page-pulse;animation-duration:var(--_shiny-pulse-speed);animation-direction:alternate;animation-iteration-count:infinite;animation-timing-function:ease-in-out;content:""}[data-shiny-busy-pulse]:not([data-shiny-busy-spinners]).shiny-busy:has(#shiny-disconnected-overlay):after{display:none}@keyframes fade-in{0%{opacity:0}to{opacity:1}}@keyframes busy-page-pulse{0%{left:-14%;right:97%}45%{left:0%;right:14%}55%{left:14%;right:0%}to{left:97%;right:-14%}}.shiny-spinner-output-container{--shiny-spinner-size: 0px}
/*! shiny 1.11.0 | (c) 2012-2025 Posit Software, PBC. | License: GPL-3 | file LICENSE */
:where([data-shiny-busy-spinners] .recalculating){position:relative}[data-shiny-busy-spinners] .recalculating{min-height:var(--shiny-spinner-size, 32px)}[data-shiny-busy-spinners] .recalculating:after{position:absolute;content:"";--_shiny-spinner-url: var(--shiny-spinner-url, url(spinners/ring.svg));--_shiny-spinner-color: var(--shiny-spinner-color, var(--bs-primary, #007bc2));--_shiny-spinner-size: var(--shiny-spinner-size, 32px);--_shiny-spinner-delay: var(--shiny-spinner-delay, 1s);background:var(--_shiny-spinner-color);width:var(--_shiny-spinner-size);height:var(--_shiny-spinner-size);inset:calc(50% - var(--_shiny-spinner-size) / 2);mask-image:var(--_shiny-spinner-url);-webkit-mask-image:var(--_shiny-spinner-url);opacity:0;animation-delay:var(--_shiny-spinner-delay);animation-name:fade-in;animation-duration:.25s;animation-fill-mode:forwards}[data-shiny-busy-spinners] .recalculating:has(>*),[data-shiny-busy-spinners] .recalculating:empty{opacity:1}[data-shiny-busy-spinners] .recalculating>*:not(.recalculating){opacity:var(--_shiny-fade-opacity);transition:opacity .25s ease var(--shiny-spinner-delay, 1s)}[data-shiny-busy-spinners] .recalculating.html-widget-output{visibility:inherit!important}[data-shiny-busy-spinners] .recalculating.html-widget-output>*{visibility:hidden}[data-shiny-busy-spinners] .recalculating.html-widget-output :after{visibility:visible}[data-shiny-busy-spinners] .recalculating.shiny-html-output:not(.shiny-table-output):after{display:none}[data-shiny-busy-spinners][data-shiny-busy-pulse].shiny-busy:after{--_shiny-pulse-background: var( --shiny-pulse-background, linear-gradient( 120deg, transparent, var(--bs-indigo, #4b00c1), var(--bs-purple, #74149c), var(--bs-pink, #bf007f), transparent ) );--_shiny-pulse-height: var(--shiny-pulse-height, 3px);--_shiny-pulse-speed: var(--shiny-pulse-speed, 1.2s);position:fixed;top:0;left:0;height:var(--_shiny-pulse-height);background:var(--_shiny-pulse-background);z-index:9999;animation-name:busy-page-pulse;animation-duration:var(--_shiny-pulse-speed);animation-direction:alternate;animation-iteration-count:infinite;animation-timing-function:ease-in-out;content:""}[data-shiny-busy-spinners][data-shiny-busy-pulse].shiny-busy:has(.recalculating:not(.shiny-html-output)):after{display:none}[data-shiny-busy-spinners][data-shiny-busy-pulse].shiny-busy:has(.recalculating.shiny-table-output):after{display:none}[data-shiny-busy-spinners][data-shiny-busy-pulse].shiny-busy:has(#shiny-disconnected-overlay):after{display:none}[data-shiny-busy-pulse]:not([data-shiny-busy-spinners]).shiny-busy:after{--_shiny-pulse-background: var( --shiny-pulse-background, linear-gradient( 120deg, transparent, var(--bs-indigo, #4b00c1), var(--bs-purple, #74149c), var(--bs-pink, #bf007f), transparent ) );--_shiny-pulse-height: var(--shiny-pulse-height, 3px);--_shiny-pulse-speed: var(--shiny-pulse-speed, 1.2s);position:fixed;top:0;left:0;height:var(--_shiny-pulse-height);background:var(--_shiny-pulse-background);z-index:9999;animation-name:busy-page-pulse;animation-duration:var(--_shiny-pulse-speed);animation-direction:alternate;animation-iteration-count:infinite;animation-timing-function:ease-in-out;content:""}[data-shiny-busy-pulse]:not([data-shiny-busy-spinners]).shiny-busy:has(#shiny-disconnected-overlay):after{display:none}@keyframes fade-in{0%{opacity:0}to{opacity:1}}@keyframes busy-page-pulse{0%{left:-14%;right:97%}45%{left:0%;right:14%}55%{left:14%;right:0%}to{left:97%;right:-14%}}.shiny-spinner-output-container{--shiny-spinner-size: 0px}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,5 @@
Authors ordered by first contribution
A list of current team members is available at http://jqueryui.com/about
A list of current team members is available at https://jqueryui.com/about
Paul Bakaus <paul.bakaus@gmail.com>
Richard Worth <rdworth@gmail.com>
@@ -42,7 +42,7 @@ Adam Sontag <ajpiano@ajpiano.com>
Carl Fürstenberg <carl@excito.com>
Kevin Dalman <development@allpro.net>
Alberto Fernández Capel <afcapel@gmail.com>
Jacek Jędrzejewski (http://jacek.jedrzejewski.name)
Jacek Jędrzejewski (https://jacek.jedrzejewski.name)
Ting Kuei <ting@kuei.com>
Samuel Cormier-Iijima <sam@chide.it>
Jon Palmer <jonspalmer@gmail.com>
@@ -370,3 +370,15 @@ dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Adam Lidén Hällgren <adamlh92@gmail.com>
James Hinderks <hinderks@gmail.com>
Denny Septian Panggabean <97607754+ddevsr@users.noreply.github.com>
Matías Cánepa <matias.canepa@gmail.com>
Ashish Kurmi <100655670+boahc077@users.noreply.github.com>
DeerBear <andrea.raimondi@gmail.com>
Дилян Палаузов <dpa-github@aegee.org>
Kenneth DeBacker <kcdebacker@gmail.com>
Timo Tijhof <krinkle@fastmail.com>
Timmy Willison <timmywil@users.noreply.github.com>
divdeploy <166095818+divdeploy@users.noreply.github.com>
mark van tilburg <markvantilburg@gmail.com>
Ralf Koller <1665422+rpkoller@users.noreply.github.com>
Porter Clevidence <116387727+porterclev@users.noreply.github.com>
Daniel García <93217193+Daniel-Garmig@users.noreply.github.com>

View File

@@ -1,4 +1,4 @@
Copyright jQuery Foundation and other contributors, https://jquery.org/
Copyright OpenJS Foundation and other contributors, https://openjsf.org/
This software consists of voluntary contributions made by many
individuals. For exact contribution history, see the revision history

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@@ -437,7 +437,7 @@ $( "#button-icon" ).button({
showLabel: false
});
$( "#radioset" ).buttonset();
$( "#radioset" ).controlgroup();
$( "#controlgroup" ).controlgroup();

View File

@@ -1,8 +1,8 @@
/*! jQuery UI - v1.13.2 - 2022-07-14
* http://jqueryui.com
/*! jQuery UI - v1.14.1 - 2024-10-30
* https://jqueryui.com
* Includes: core.css, accordion.css, autocomplete.css, menu.css, button.css, controlgroup.css, checkboxradio.css, datepicker.css, dialog.css, draggable.css, resizable.css, progressbar.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css
* To view and modify this theme, visit http://jqueryui.com/themeroller/?bgShadowXPos=&bgOverlayXPos=&bgErrorXPos=&bgHighlightXPos=&bgContentXPos=&bgHeaderXPos=&bgActiveXPos=&bgHoverXPos=&bgDefaultXPos=&bgShadowYPos=&bgOverlayYPos=&bgErrorYPos=&bgHighlightYPos=&bgContentYPos=&bgHeaderYPos=&bgActiveYPos=&bgHoverYPos=&bgDefaultYPos=&bgShadowRepeat=&bgOverlayRepeat=&bgErrorRepeat=&bgHighlightRepeat=&bgContentRepeat=&bgHeaderRepeat=&bgActiveRepeat=&bgHoverRepeat=&bgDefaultRepeat=&iconsHover=url(%22images%2Fui-icons_555555_256x240.png%22)&iconsHighlight=url(%22images%2Fui-icons_777620_256x240.png%22)&iconsHeader=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsError=url(%22images%2Fui-icons_cc0000_256x240.png%22)&iconsDefault=url(%22images%2Fui-icons_777777_256x240.png%22)&iconsContent=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsActive=url(%22images%2Fui-icons_ffffff_256x240.png%22)&bgImgUrlShadow=&bgImgUrlOverlay=&bgImgUrlHover=&bgImgUrlHighlight=&bgImgUrlHeader=&bgImgUrlError=&bgImgUrlDefault=&bgImgUrlContent=&bgImgUrlActive=&opacityFilterShadow=Alpha(Opacity%3D30)&opacityFilterOverlay=Alpha(Opacity%3D30)&opacityShadowPerc=30&opacityOverlayPerc=30&iconColorHover=%23555555&iconColorHighlight=%23777620&iconColorHeader=%23444444&iconColorError=%23cc0000&iconColorDefault=%23777777&iconColorContent=%23444444&iconColorActive=%23ffffff&bgImgOpacityShadow=0&bgImgOpacityOverlay=0&bgImgOpacityError=95&bgImgOpacityHighlight=55&bgImgOpacityContent=75&bgImgOpacityHeader=75&bgImgOpacityActive=65&bgImgOpacityHover=75&bgImgOpacityDefault=75&bgTextureShadow=flat&bgTextureOverlay=flat&bgTextureError=flat&bgTextureHighlight=flat&bgTextureContent=flat&bgTextureHeader=flat&bgTextureActive=flat&bgTextureHover=flat&bgTextureDefault=flat&cornerRadius=3px&fwDefault=normal&ffDefault=Arial%2CHelvetica%2Csans-serif&fsDefault=1em&cornerRadiusShadow=8px&thicknessShadow=5px&offsetLeftShadow=0px&offsetTopShadow=0px&opacityShadow=.3&bgColorShadow=%23666666&opacityOverlay=.3&bgColorOverlay=%23aaaaaa&fcError=%235f3f3f&borderColorError=%23f1a899&bgColorError=%23fddfdf&fcHighlight=%23777620&borderColorHighlight=%23dad55e&bgColorHighlight=%23fffa90&fcContent=%23333333&borderColorContent=%23dddddd&bgColorContent=%23ffffff&fcHeader=%23333333&borderColorHeader=%23dddddd&bgColorHeader=%23e9e9e9&fcActive=%23ffffff&borderColorActive=%23003eff&bgColorActive=%23007fff&fcHover=%232b2b2b&borderColorHover=%23cccccc&bgColorHover=%23ededed&fcDefault=%23454545&borderColorDefault=%23c5c5c5&bgColorDefault=%23f6f6f6
* Copyright jQuery Foundation and other contributors; Licensed MIT */
* To view and modify this theme, visit https://jqueryui.com/themeroller/?bgColorDefault=%23f6f6f6&borderColorDefault=%23c5c5c5&fcDefault=%23454545&bgColorHover=%23ededed&borderColorHover=%23cccccc&fcHover=%232b2b2b&bgColorActive=%23007fff&borderColorActive=%23003eff&fcActive=%23ffffff&bgColorHeader=%23e9e9e9&borderColorHeader=%23dddddd&fcHeader=%23333333&bgColorContent=%23ffffff&borderColorContent=%23dddddd&fcContent=%23333333&bgColorHighlight=%23fffa90&borderColorHighlight=%23dad55e&fcHighlight=%23777620&bgColorError=%23fddfdf&borderColorError=%23f1a899&fcError=%235f3f3f&bgColorOverlay=%23aaaaaa&opacityOverlay=.3&bgColorShadow=%23666666&opacityShadow=.3&offsetTopShadow=0px&offsetLeftShadow=0px&thicknessShadow=5px&cornerRadiusShadow=8px&fsDefault=1em&ffDefault=Arial%2CHelvetica%2Csans-serif&fwDefault=normal&cornerRadius=3px&bgTextureDefault=flat&bgTextureHover=flat&bgTextureActive=flat&bgTextureHeader=flat&bgTextureContent=flat&bgTextureHighlight=flat&bgTextureError=flat&bgTextureOverlay=flat&bgTextureShadow=flat&bgImgOpacityDefault=75&bgImgOpacityHover=75&bgImgOpacityActive=65&bgImgOpacityHeader=75&bgImgOpacityContent=75&bgImgOpacityHighlight=55&bgImgOpacityError=95&bgImgOpacityOverlay=0&bgImgOpacityShadow=0&iconColorActive=%23ffffff&iconColorContent=%23444444&iconColorDefault=%23777777&iconColorError=%23cc0000&iconColorHeader=%23444444&iconColorHighlight=%23777620&iconColorHover=%23555555&opacityOverlayPerc=30&opacityShadowPerc=30&bgImgUrlActive=&bgImgUrlContent=&bgImgUrlDefault=&bgImgUrlError=&bgImgUrlHeader=&bgImgUrlHighlight=&bgImgUrlHover=&bgImgUrlOverlay=&bgImgUrlShadow=&iconsActive=url(%22images%2Fui-icons_ffffff_256x240.png%22)&iconsContent=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsDefault=url(%22images%2Fui-icons_777777_256x240.png%22)&iconsError=url(%22images%2Fui-icons_cc0000_256x240.png%22)&iconsHeader=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsHighlight=url(%22images%2Fui-icons_777620_256x240.png%22)&iconsHover=url(%22images%2Fui-icons_555555_256x240.png%22)&bgDefaultRepeat=&bgHoverRepeat=&bgActiveRepeat=&bgHeaderRepeat=&bgContentRepeat=&bgHighlightRepeat=&bgErrorRepeat=&bgOverlayRepeat=&bgShadowRepeat=&bgDefaultYPos=&bgHoverYPos=&bgActiveYPos=&bgHeaderYPos=&bgContentYPos=&bgHighlightYPos=&bgErrorYPos=&bgOverlayYPos=&bgShadowYPos=&bgDefaultXPos=&bgHoverXPos=&bgActiveXPos=&bgHeaderXPos=&bgContentXPos=&bgHighlightXPos=&bgErrorXPos=&bgOverlayXPos=&bgShadowXPos=
* Copyright OpenJS Foundation and other contributors; Licensed MIT */
/* Layout helpers
----------------------------------*/
@@ -45,7 +45,6 @@
left: 0;
position: absolute;
opacity: 0;
-ms-filter: "alpha(opacity=0)"; /* support: IE8 */
}
.ui-front {
@@ -122,8 +121,6 @@
.ui-menu .ui-menu-item {
margin: 0;
cursor: pointer;
/* support: IE10, see #8844 */
list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
}
.ui-menu .ui-menu-item-wrapper {
position: relative;
@@ -173,12 +170,7 @@
vertical-align: middle;
text-align: center;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
/* Support: IE <= 11 */
overflow: visible;
}
.ui-button,
@@ -229,7 +221,7 @@ input.ui-button.ui-icon-notext .ui-icon {
}
/* workarounds */
/* Support: Firefox 5 - 40 */
/* Support: Firefox 5 - 125+ */
input.ui-button::-moz-focus-inner,
button.ui-button::-moz-focus-inner {
border: 0;
@@ -280,9 +272,6 @@ button.ui-button::-moz-focus-inner {
/* Spinner specific style fixes */
.ui-controlgroup-vertical .ui-spinner-input {
/* Support: IE8 only, Android < 4.4 only */
width: 75%;
width: calc( 100% - 2.4em );
}
.ui-controlgroup-vertical .ui-spinner .ui-spinner-up {
@@ -579,7 +568,6 @@ button.ui-button::-moz-focus-inner {
cursor: move;
}
.ui-draggable-handle {
-ms-touch-action: none;
touch-action: none;
}
.ui-resizable {
@@ -589,7 +577,6 @@ button.ui-button::-moz-focus-inner {
position: absolute;
font-size: 0.1px;
display: block;
-ms-touch-action: none;
touch-action: none;
}
.ui-resizable-disabled .ui-resizable-handle,
@@ -664,14 +651,12 @@ button.ui-button::-moz-focus-inner {
.ui-progressbar .ui-progressbar-overlay {
background: url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");
height: 100%;
-ms-filter: "alpha(opacity=25)"; /* support: IE8 */
opacity: 0.25;
}
.ui-progressbar-indeterminate .ui-progressbar-value {
background-image: none;
}
.ui-selectable {
-ms-touch-action: none;
touch-action: none;
}
.ui-selectable-helper {
@@ -729,7 +714,6 @@ button.ui-button::-moz-focus-inner {
width: 1.2em;
height: 1.2em;
cursor: pointer;
-ms-touch-action: none;
touch-action: none;
}
.ui-slider .ui-slider-range {
@@ -741,12 +725,6 @@ button.ui-button::-moz-focus-inner {
background-position: 0 0;
}
/* support: IE8 - See #6727 */
.ui-slider.ui-state-disabled .ui-slider-handle,
.ui-slider.ui-state-disabled .ui-slider-range {
filter: inherit;
}
.ui-slider-horizontal {
height: .8em;
}
@@ -785,7 +763,6 @@ button.ui-button::-moz-focus-inner {
top: 0;
}
.ui-sortable-handle {
-ms-touch-action: none;
touch-action: none;
}
.ui-spinner {
@@ -1041,19 +1018,14 @@ a.ui-button:active,
.ui-widget-content .ui-priority-secondary,
.ui-widget-header .ui-priority-secondary {
opacity: .7;
-ms-filter: "alpha(opacity=70)"; /* support: IE8 */
font-weight: normal;
}
.ui-state-disabled,
.ui-widget-content .ui-state-disabled,
.ui-widget-header .ui-state-disabled {
opacity: .35;
-ms-filter: "alpha(opacity=35)"; /* support: IE8 */
background-image: none;
}
.ui-state-disabled .ui-icon {
-ms-filter: "alpha(opacity=35)"; /* support: IE8 - See #6059 */
}
/* Icons
----------------------------------*/
@@ -1306,10 +1278,8 @@ a.ui-button:active,
/* Overlays */
.ui-widget-overlay {
background: #aaaaaa;
opacity: .003;
-ms-filter: Alpha(Opacity=.3); /* support: IE8 */
opacity: .3;
}
.ui-widget-shadow {
-webkit-box-shadow: 0px 0px 5px #666666;
box-shadow: 0px 0px 5px #666666;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,12 +1,12 @@
/*!
* jQuery UI CSS Framework 1.13.2
* http://jqueryui.com
* jQuery UI CSS Framework 1.14.1
* https://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Copyright OpenJS Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
* https://jquery.org/license
*
* http://api.jqueryui.com/category/theming/
* https://api.jqueryui.com/category/theming/
*/
/* Layout helpers
----------------------------------*/
@@ -49,7 +49,6 @@
left: 0;
position: absolute;
opacity: 0;
-ms-filter: "alpha(opacity=0)"; /* support: IE8 */
}
.ui-front {
@@ -126,8 +125,6 @@
.ui-menu .ui-menu-item {
margin: 0;
cursor: pointer;
/* support: IE10, see #8844 */
list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
}
.ui-menu .ui-menu-item-wrapper {
position: relative;
@@ -177,12 +174,7 @@
vertical-align: middle;
text-align: center;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
/* Support: IE <= 11 */
overflow: visible;
}
.ui-button,
@@ -233,7 +225,7 @@ input.ui-button.ui-icon-notext .ui-icon {
}
/* workarounds */
/* Support: Firefox 5 - 40 */
/* Support: Firefox 5 - 125+ */
input.ui-button::-moz-focus-inner,
button.ui-button::-moz-focus-inner {
border: 0;
@@ -284,9 +276,6 @@ button.ui-button::-moz-focus-inner {
/* Spinner specific style fixes */
.ui-controlgroup-vertical .ui-spinner-input {
/* Support: IE8 only, Android < 4.4 only */
width: 75%;
width: calc( 100% - 2.4em );
}
.ui-controlgroup-vertical .ui-spinner .ui-spinner-up {
@@ -583,7 +572,6 @@ button.ui-button::-moz-focus-inner {
cursor: move;
}
.ui-draggable-handle {
-ms-touch-action: none;
touch-action: none;
}
.ui-resizable {
@@ -593,7 +581,6 @@ button.ui-button::-moz-focus-inner {
position: absolute;
font-size: 0.1px;
display: block;
-ms-touch-action: none;
touch-action: none;
}
.ui-resizable-disabled .ui-resizable-handle,
@@ -668,14 +655,12 @@ button.ui-button::-moz-focus-inner {
.ui-progressbar .ui-progressbar-overlay {
background: url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");
height: 100%;
-ms-filter: "alpha(opacity=25)"; /* support: IE8 */
opacity: 0.25;
}
.ui-progressbar-indeterminate .ui-progressbar-value {
background-image: none;
}
.ui-selectable {
-ms-touch-action: none;
touch-action: none;
}
.ui-selectable-helper {
@@ -733,7 +718,6 @@ button.ui-button::-moz-focus-inner {
width: 1.2em;
height: 1.2em;
cursor: pointer;
-ms-touch-action: none;
touch-action: none;
}
.ui-slider .ui-slider-range {
@@ -745,12 +729,6 @@ button.ui-button::-moz-focus-inner {
background-position: 0 0;
}
/* support: IE8 - See #6727 */
.ui-slider.ui-state-disabled .ui-slider-handle,
.ui-slider.ui-state-disabled .ui-slider-range {
filter: inherit;
}
.ui-slider-horizontal {
height: .8em;
}
@@ -789,7 +767,6 @@ button.ui-button::-moz-focus-inner {
top: 0;
}
.ui-sortable-handle {
-ms-touch-action: none;
touch-action: none;
}
.ui-spinner {

File diff suppressed because one or more lines are too long

View File

@@ -1,14 +1,14 @@
/*!
* jQuery UI CSS Framework 1.13.2
* http://jqueryui.com
* jQuery UI CSS Framework 1.14.1
* https://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Copyright OpenJS Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
* https://jquery.org/license
*
* http://api.jqueryui.com/category/theming/
* https://api.jqueryui.com/category/theming/
*
* To view and modify this theme, visit http://jqueryui.com/themeroller/?bgShadowXPos=&bgOverlayXPos=&bgErrorXPos=&bgHighlightXPos=&bgContentXPos=&bgHeaderXPos=&bgActiveXPos=&bgHoverXPos=&bgDefaultXPos=&bgShadowYPos=&bgOverlayYPos=&bgErrorYPos=&bgHighlightYPos=&bgContentYPos=&bgHeaderYPos=&bgActiveYPos=&bgHoverYPos=&bgDefaultYPos=&bgShadowRepeat=&bgOverlayRepeat=&bgErrorRepeat=&bgHighlightRepeat=&bgContentRepeat=&bgHeaderRepeat=&bgActiveRepeat=&bgHoverRepeat=&bgDefaultRepeat=&iconsHover=url(%22images%2Fui-icons_555555_256x240.png%22)&iconsHighlight=url(%22images%2Fui-icons_777620_256x240.png%22)&iconsHeader=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsError=url(%22images%2Fui-icons_cc0000_256x240.png%22)&iconsDefault=url(%22images%2Fui-icons_777777_256x240.png%22)&iconsContent=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsActive=url(%22images%2Fui-icons_ffffff_256x240.png%22)&bgImgUrlShadow=&bgImgUrlOverlay=&bgImgUrlHover=&bgImgUrlHighlight=&bgImgUrlHeader=&bgImgUrlError=&bgImgUrlDefault=&bgImgUrlContent=&bgImgUrlActive=&opacityFilterShadow=Alpha(Opacity%3D30)&opacityFilterOverlay=Alpha(Opacity%3D30)&opacityShadowPerc=30&opacityOverlayPerc=30&iconColorHover=%23555555&iconColorHighlight=%23777620&iconColorHeader=%23444444&iconColorError=%23cc0000&iconColorDefault=%23777777&iconColorContent=%23444444&iconColorActive=%23ffffff&bgImgOpacityShadow=0&bgImgOpacityOverlay=0&bgImgOpacityError=95&bgImgOpacityHighlight=55&bgImgOpacityContent=75&bgImgOpacityHeader=75&bgImgOpacityActive=65&bgImgOpacityHover=75&bgImgOpacityDefault=75&bgTextureShadow=flat&bgTextureOverlay=flat&bgTextureError=flat&bgTextureHighlight=flat&bgTextureContent=flat&bgTextureHeader=flat&bgTextureActive=flat&bgTextureHover=flat&bgTextureDefault=flat&cornerRadius=3px&fwDefault=normal&ffDefault=Arial%2CHelvetica%2Csans-serif&fsDefault=1em&cornerRadiusShadow=8px&thicknessShadow=5px&offsetLeftShadow=0px&offsetTopShadow=0px&opacityShadow=.3&bgColorShadow=%23666666&opacityOverlay=.3&bgColorOverlay=%23aaaaaa&fcError=%235f3f3f&borderColorError=%23f1a899&bgColorError=%23fddfdf&fcHighlight=%23777620&borderColorHighlight=%23dad55e&bgColorHighlight=%23fffa90&fcContent=%23333333&borderColorContent=%23dddddd&bgColorContent=%23ffffff&fcHeader=%23333333&borderColorHeader=%23dddddd&bgColorHeader=%23e9e9e9&fcActive=%23ffffff&borderColorActive=%23003eff&bgColorActive=%23007fff&fcHover=%232b2b2b&borderColorHover=%23cccccc&bgColorHover=%23ededed&fcDefault=%23454545&borderColorDefault=%23c5c5c5&bgColorDefault=%23f6f6f6
* To view and modify this theme, visit https://jqueryui.com/themeroller/?bgColorDefault=%23f6f6f6&borderColorDefault=%23c5c5c5&fcDefault=%23454545&bgColorHover=%23ededed&borderColorHover=%23cccccc&fcHover=%232b2b2b&bgColorActive=%23007fff&borderColorActive=%23003eff&fcActive=%23ffffff&bgColorHeader=%23e9e9e9&borderColorHeader=%23dddddd&fcHeader=%23333333&bgColorContent=%23ffffff&borderColorContent=%23dddddd&fcContent=%23333333&bgColorHighlight=%23fffa90&borderColorHighlight=%23dad55e&fcHighlight=%23777620&bgColorError=%23fddfdf&borderColorError=%23f1a899&fcError=%235f3f3f&bgColorOverlay=%23aaaaaa&opacityOverlay=.3&bgColorShadow=%23666666&opacityShadow=.3&offsetTopShadow=0px&offsetLeftShadow=0px&thicknessShadow=5px&cornerRadiusShadow=8px&fsDefault=1em&ffDefault=Arial%2CHelvetica%2Csans-serif&fwDefault=normal&cornerRadius=3px&bgTextureDefault=flat&bgTextureHover=flat&bgTextureActive=flat&bgTextureHeader=flat&bgTextureContent=flat&bgTextureHighlight=flat&bgTextureError=flat&bgTextureOverlay=flat&bgTextureShadow=flat&bgImgOpacityDefault=75&bgImgOpacityHover=75&bgImgOpacityActive=65&bgImgOpacityHeader=75&bgImgOpacityContent=75&bgImgOpacityHighlight=55&bgImgOpacityError=95&bgImgOpacityOverlay=0&bgImgOpacityShadow=0&iconColorActive=%23ffffff&iconColorContent=%23444444&iconColorDefault=%23777777&iconColorError=%23cc0000&iconColorHeader=%23444444&iconColorHighlight=%23777620&iconColorHover=%23555555&opacityOverlayPerc=30&opacityShadowPerc=30&bgImgUrlActive=&bgImgUrlContent=&bgImgUrlDefault=&bgImgUrlError=&bgImgUrlHeader=&bgImgUrlHighlight=&bgImgUrlHover=&bgImgUrlOverlay=&bgImgUrlShadow=&iconsActive=url(%22images%2Fui-icons_ffffff_256x240.png%22)&iconsContent=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsDefault=url(%22images%2Fui-icons_777777_256x240.png%22)&iconsError=url(%22images%2Fui-icons_cc0000_256x240.png%22)&iconsHeader=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsHighlight=url(%22images%2Fui-icons_777620_256x240.png%22)&iconsHover=url(%22images%2Fui-icons_555555_256x240.png%22)&bgDefaultRepeat=&bgHoverRepeat=&bgActiveRepeat=&bgHeaderRepeat=&bgContentRepeat=&bgHighlightRepeat=&bgErrorRepeat=&bgOverlayRepeat=&bgShadowRepeat=&bgDefaultYPos=&bgHoverYPos=&bgActiveYPos=&bgHeaderYPos=&bgContentYPos=&bgHighlightYPos=&bgErrorYPos=&bgOverlayYPos=&bgShadowYPos=&bgDefaultXPos=&bgHoverXPos=&bgActiveXPos=&bgHeaderXPos=&bgContentXPos=&bgHighlightXPos=&bgErrorXPos=&bgOverlayXPos=&bgShadowXPos=
*/
@@ -172,19 +172,14 @@ a.ui-button:active,
.ui-widget-content .ui-priority-secondary,
.ui-widget-header .ui-priority-secondary {
opacity: .7;
-ms-filter: "alpha(opacity=70)"; /* support: IE8 */
font-weight: normal;
}
.ui-state-disabled,
.ui-widget-content .ui-state-disabled,
.ui-widget-header .ui-state-disabled {
opacity: .35;
-ms-filter: "alpha(opacity=35)"; /* support: IE8 */
background-image: none;
}
.ui-state-disabled .ui-icon {
-ms-filter: "alpha(opacity=35)"; /* support: IE8 - See #6059 */
}
/* Icons
----------------------------------*/
@@ -437,10 +432,8 @@ a.ui-button:active,
/* Overlays */
.ui-widget-overlay {
background: #aaaaaa;
opacity: .003;
-ms-filter: Alpha(Opacity=.3); /* support: IE8 */
opacity: .3;
}
.ui-widget-shadow {
-webkit-box-shadow: 0px 0px 5px #666666;
box-shadow: 0px 0px 5px #666666;
}

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
Selectize.define("selectize-plugin-a11y",function(c){var t=this,l=13;typeof t.accessibility=="undefined"&&(t.accessibility={}),t.accessibility.helpers={randomId:function(e){for(var r="",s=e||10,i="abcdefghijklmnopqrstuvwxyz0123456789",n=i.length,a=0;a<s;a++)r+=i[Math.floor(n*Math.random())];return r}},t.accessibility.liveRegion={$region:"",speak:function(e){var r=$("<div></div>");r.text(e),this.$region.html(r)},domListener:function(){var e=new MutationObserver(function(r){r.forEach(function(s){var i=$(s.target);if(i.hasClass("items"))if(i.hasClass("dropdown-active")){t.$control_input.attr("aria-expanded","true");for(var n=t.$dropdown_content[0].children,a=0;a<n.length;a++){var o=n[a].attributes;o.role||n[a].setAttribute("role","option"),o.id||n[a].setAttribute("id",t.accessibility.helpers.randomId())}}else t.$control_input.attr("aria-expanded","false"),t.$control_input.removeAttr("aria-activedescendant");else i.hasClass("active")&&i.attr("data-value")&&(t.$control_input.attr("aria-activedescendant",i.attr("id")),t.accessibility.liveRegion.speak(i.text(),500))})});e.observe(t.$dropdown[0],{attributes:!0,attributeFilter:["class"],subtree:!0,attributeOldValue:!0}),e.observe(t.$control[0],{attributes:!0,attributeFilter:["class"]}),e.observe(t.$control_input[0],{attributes:!0,attributeFilter:["value"]})},setAttributes:function(){this.$region.attr({"aria-live":"assertive",role:"log","aria-relevant":"additions","aria-atomic":"true"})},setStyles:function(){this.$region.css({position:"absolute",width:"1px",height:"1px","margin-top":"-1px",clip:"rect(1px, 1px, 1px, 1px)",overflow:"hidden"})},init:function(){this.$region=$("<div>"),this.setAttributes(),this.setStyles(),$("body").append(this.$region),this.domListener()}},this.setup=function(){var e=t.setup;return function(){e.apply(this,arguments);var r=t.accessibility.helpers.randomId(),s=t.accessibility.helpers.randomId();t.$control.on("keydown",function(i){i.keyCode===l&&(t.settings.openOnFocus?(t.settings.openOnFocus=!1,t.focus(),setTimeout(function(){t.settings.openOnFocus=!0},0)):t.focus())}),t.$control_input.attr({role:"combobox","aria-expanded":"false",haspopup:"listbox","aria-owns":s,"aria-label":t.$wrapper.closest("[data-accessibility-selectize-label]").attr("data-accessibility-selectize-label")}),t.$dropdown_content.attr({role:"listbox",id:s}),t.accessibility.liveRegion.init()}}(),this.destroy=function(){var e=t.destroy;return function(){return t.accessibility.liveRegion.$region.remove(),e.apply(this,arguments)}}()});
Selectize.define("selectize-plugin-a11y",function(c){var t=this,l=13;typeof t.accessibility>"u"&&(t.accessibility={}),t.accessibility.helpers={randomId:function(e){for(var r="",s=e||10,i="abcdefghijklmnopqrstuvwxyz0123456789",n=i.length,a=0;a<s;a++)r+=i[Math.floor(n*Math.random())];return r}},t.accessibility.liveRegion={$region:"",speak:function(e){var r=$("<div></div>");r.text(e),this.$region.html(r)},domListener:function(){var e=new MutationObserver(function(r){r.forEach(function(s){var i=$(s.target);if(i.hasClass("items"))if(i.hasClass("dropdown-active")){t.$control_input.attr("aria-expanded","true");for(var n=t.$dropdown_content[0].children,a=0;a<n.length;a++){var o=n[a].attributes;o.role||n[a].setAttribute("role","option"),o.id||n[a].setAttribute("id",t.accessibility.helpers.randomId())}}else t.$control_input.attr("aria-expanded","false"),t.$control_input.removeAttr("aria-activedescendant");else i.hasClass("active")&&i.attr("data-value")&&(t.$control_input.attr("aria-activedescendant",i.attr("id")),t.accessibility.liveRegion.speak(i.text(),500))})});e.observe(t.$dropdown[0],{attributes:!0,attributeFilter:["class"],subtree:!0,attributeOldValue:!0}),e.observe(t.$control[0],{attributes:!0,attributeFilter:["class"]}),e.observe(t.$control_input[0],{attributes:!0,attributeFilter:["value"]})},setAttributes:function(){this.$region.attr({"aria-live":"assertive",role:"log","aria-relevant":"additions","aria-atomic":"true"})},setStyles:function(){this.$region.css({position:"absolute",width:"1px",height:"1px","margin-top":"-1px",clip:"rect(1px, 1px, 1px, 1px)",overflow:"hidden"})},init:function(){this.$region=$("<div>"),this.setAttributes(),this.setStyles(),$("body").append(this.$region),this.domListener()}},this.setup=function(){var e=t.setup;return function(){e.apply(this,arguments);var r=t.accessibility.helpers.randomId(),s=t.accessibility.helpers.randomId();t.$control.on("keydown",function(i){i.keyCode===l&&(t.settings.openOnFocus?(t.settings.openOnFocus=!1,t.focus(),setTimeout(function(){t.settings.openOnFocus=!0},0)):t.focus())}),t.$control_input.attr({role:"combobox","aria-expanded":"false",haspopup:"listbox","aria-owns":s,"aria-label":t.$wrapper.closest("[data-accessibility-selectize-label]").attr("data-accessibility-selectize-label")}),t.$dropdown_content.attr({role:"listbox",id:s}),t.accessibility.liveRegion.init()}}(),this.destroy=function(){var e=t.destroy;return function(){return t.accessibility.liveRegion.$region.remove(),e.apply(this,arguments)}}()});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,2 @@
/*! shiny 1.10.0.9000 | (c) 2012-2025 Posit Software, PBC. | License: GPL-3 | file LICENSE */
/*! shiny 1.11.0 | (c) 2012-2025 Posit Software, PBC. | License: GPL-3 | file LICENSE */
#showcase-well{border-radius:0}.shiny-code{background-color:#fff;margin-bottom:0}.shiny-code code{font-family:Menlo,Consolas,Courier New,monospace}.shiny-code-container{margin-top:20px;clear:both}.shiny-code-container h3{display:inline;margin-right:15px}.showcase-header{font-size:16px;font-weight:400}.showcase-code-link{text-align:right;padding:15px}#showcase-app-container{vertical-align:top}#showcase-code-tabs{margin-right:15px}#showcase-code-tabs pre{border:none;line-height:1em}#showcase-code-tabs .nav,#showcase-code-tabs ul{margin-bottom:0}#showcase-code-tabs .tab-content{border-style:solid;border-color:#e5e5e5;border-width:0px 1px 1px 1px;overflow:auto;border-bottom-right-radius:4px;border-bottom-left-radius:4px}#showcase-app-code{width:100%}#showcase-code-position-toggle{float:right}#showcase-sxs-code{padding-top:20px;vertical-align:top}.showcase-code-license{display:block;text-align:right}#showcase-code-content pre{background-color:#fff}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +1,3 @@
/*! shiny 1.10.0.9000 | (c) 2012-2025 Posit Software, PBC. | License: GPL-3 | file LICENSE */
"use strict";(function(){var a=eval;window.addEventListener("message",function(i){var e=i.data;e.code&&a(e.code)});})();
/*! shiny 1.11.0 | (c) 2012-2025 Posit Software, PBC. | License: GPL-3 | file LICENSE */
"use strict";(()=>{var t=eval;window.addEventListener("message",function(a){let e=a.data;e.code&&t(e.code)});})();
//# sourceMappingURL=shiny-testmode.js.map

View File

@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../../srcts/src/utils/eval.ts", "../../../srcts/extras/shiny-testmode.ts"],
"sourcesContent": ["//esbuild.github.io/content-types/#direct-eval\n//tl/dr;\n// * Direct usage of `eval(\"x\")` is bad with bundled code.\n// * Instead, use indirect calls to `eval` such as `indirectEval(\"x\")`\n// * Even just renaming the function works well enough.\n// > This is known as \"indirect eval\" because eval is not being called directly, and so does not trigger the grammatical special case for direct eval in the JavaScript VM. You can call indirect eval using any syntax at all except for an expression of the exact form eval('x'). For example, var eval2 = eval; eval2('x') and [eval][0]('x') and window.eval('x') are all indirect eval calls.\n// > When you use indirect eval, the code is evaluated in the global scope instead of in the inline scope of the caller.\n\nvar indirectEval = eval;\nexport { indirectEval };", "/* eslint-disable unicorn/filename-case */\nimport { indirectEval } from \"../src/utils/eval\";\n\n// Listen for messages from parent frame. This file is only added when the\n// shiny.testmode option is TRUE.\nwindow.addEventListener(\"message\", function (e) {\n var message = e.data;\n if (message.code) indirectEval(message.code);\n});"],
"mappings": ";yBAQA,IAAIA,EAAe,KCHnB,OAAO,iBAAiB,UAAW,SAAUC,EAAG,CAC9C,IAAIC,EAAUD,EAAE,KACZC,EAAQ,MAAMC,EAAaD,EAAQ,IAAI,CAC7C,CAAC",
"sourcesContent": ["//esbuild.github.io/content-types/#direct-eval\n//tl/dr;\n// * Direct usage of `eval(\"x\")` is bad with bundled code.\n// * Instead, use indirect calls to `eval` such as `indirectEval(\"x\")`\n// * Even just renaming the function works well enough.\n// > This is known as \"indirect eval\" because eval is not being called directly, and so does not trigger the grammatical special case for direct eval in the JavaScript VM. You can call indirect eval using any syntax at all except for an expression of the exact form eval('x'). For example, var eval2 = eval; eval2('x') and [eval][0]('x') and window.eval('x') are all indirect eval calls.\n// > When you use indirect eval, the code is evaluated in the global scope instead of in the inline scope of the caller.\n\nconst indirectEval = eval;\n\nexport { indirectEval };\n", "/* eslint-disable unicorn/filename-case */\nimport { indirectEval } from \"../src/utils/eval\";\n\n// Listen for messages from parent frame. This file is only added when the\n// shiny.testmode option is TRUE.\nwindow.addEventListener(\"message\", function (e: { data: { code: string } }) {\n const message = e.data;\n\n if (message.code) indirectEval(message.code);\n});\n"],
"mappings": ";mBAQA,IAAMA,EAAe,KCHrB,OAAO,iBAAiB,UAAW,SAAUC,EAA+B,CAC1E,IAAMC,EAAUD,EAAE,KAEdC,EAAQ,MAAMC,EAAaD,EAAQ,IAAI,CAC7C,CAAC",
"names": ["indirectEval", "e", "message", "indirectEval"]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -384,6 +384,14 @@ html.autoreload-enabled #shiny-disconnected-overlay.reloading {
width: 100%;
}
/* Styling for textAreaInput(autoresize=TRUE) */
textarea.textarea-autoresize.form-control {
padding: 5px 8px;
resize: none;
overflow-y: hidden;
height: auto;
}
#shiny-notification-panel {
position: fixed;

View File

@@ -46,12 +46,15 @@ session to immediately unblock and carry on with other user interactions.
}
\examples{
\dontshow{if (rlang::is_interactive() && rlang::is_installed("future")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf}
\dontshow{if (rlang::is_interactive() && rlang::is_installed("mirai")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf}
library(shiny)
library(bslib)
library(future)
plan(multisession)
library(mirai)
# Set background processes for running tasks
daemons(1)
# Reset when the app is stopped
onStop(function() daemons(0))
ui <- page_fluid(
titlePanel("Extended Task Demo"),
@@ -65,13 +68,12 @@ ui <- page_fluid(
server <- function(input, output) {
rand_task <- ExtendedTask$new(function() {
future(
mirai(
{
# Slow operation goes here
Sys.sleep(2)
sample(1:100, 1)
},
seed = TRUE
}
)
})
@@ -121,11 +123,12 @@ server function.
\item{\code{func}}{The long-running operation to execute. This should be an
asynchronous function, meaning, it should use the
\href{https://rstudio.github.io/promises/}{\{promises\}} package, most
likely in conjuction with the
likely in conjunction with the
\href{https://mirai.r-lib.org}{\{mirai\}} or
\href{https://rstudio.github.io/promises/articles/promises_04_futures.html}{\{future\}}
package. (In short, the return value of \code{func} should be a
\code{\link[future:future]{Future}} object, or a \code{promise}, or something else
that \code{\link[promises:is.promise]{promises::as.promise()}} understands.)
\code{\link[mirai:mirai]{mirai}}, \code{\link[future:future]{Future}}, \code{promise},
or something else that \code{\link[promises:is.promise]{promises::as.promise()}} understands.)
It's also important that this logic does not read from any
reactive inputs/sources, as inputs may change after the function is

View File

@@ -234,8 +234,8 @@ With a cached reactive expression, the key and/or value expression can be
promises, but rather objects provided by the
\href{https://rstudio.github.io/promises/}{\pkg{promises}} package, which
are similar to promises in JavaScript. (See \code{\link[promises:promise]{promises::promise()}} for more
information.) You can also use \code{\link[future:future]{future::future()}} objects to run code in a
separate process or even on a remote machine.
information.) You can also use \code{\link[mirai:mirai]{mirai::mirai()}} or \code{\link[future:future]{future::future()}}
objects to run code in a separate process or even on a remote machine.
If the value returns a promise, then anything that consumes the cached
reactive must expect it to return a promise.

View File

@@ -60,4 +60,14 @@ server <- function(input, output) {
shinyApp(ui, server)
}
}
\seealso{
\itemize{
\item The download handler, like other outputs, is suspended (disabled) by
default for download buttons and links that are hidden. Use
\code{\link[=outputOptions]{outputOptions()}} to control this behavior, e.g. to set
\code{suspendWhenHidden = FALSE} if the download is initiated by
programmatically clicking on the download button using JavaScript.
}
}

View File

@@ -11,7 +11,9 @@ numericInput(
min = NA,
max = NA,
step = NA,
width = NULL
width = NULL,
...,
updateOn = c("change", "blur")
)
}
\arguments{
@@ -29,6 +31,16 @@ numericInput(
\item{width}{The width of the input, e.g. \code{'400px'}, or \code{'100\%'};
see \code{\link[=validateCssUnit]{validateCssUnit()}}.}
\item{...}{Ignored, included to require named arguments and for future
feature expansion.}
\item{updateOn}{A character vector specifying when the input should be
updated. Options are \code{"change"} (default) and \code{"blur"}. Use \code{"change"} to
update the input immediately whenever the value changes. Use \code{"blur"}to
delay the input update until the input loses focus (the user moves away
from the input), or when Enter is pressed (or Cmd/Ctrl + Enter for
\code{\link[=textAreaInput]{textAreaInput()}}).}
}
\value{
A numeric input control that can be added to a UI definition.

View File

@@ -4,7 +4,15 @@
\alias{passwordInput}
\title{Create a password input control}
\usage{
passwordInput(inputId, label, value = "", width = NULL, placeholder = NULL)
passwordInput(
inputId,
label,
value = "",
width = NULL,
placeholder = NULL,
...,
updateOn = c("change", "blur")
)
}
\arguments{
\item{inputId}{The \code{input} slot that will be used to access the value.}
@@ -19,6 +27,16 @@ see \code{\link[=validateCssUnit]{validateCssUnit()}}.}
\item{placeholder}{A character string giving the user a hint as to what can
be entered into the control. Internet Explorer 8 and 9 do not support this
option.}
\item{...}{Ignored, included to require named arguments and for future
feature expansion.}
\item{updateOn}{A character vector specifying when the input should be
updated. Options are \code{"change"} (default) and \code{"blur"}. Use \code{"change"} to
update the input immediately whenever the value changes. Use \code{"blur"}to
delay the input update until the input loses focus (the user moves away
from the input), or when Enter is pressed (or Cmd/Ctrl + Enter for
\code{\link[=textAreaInput]{textAreaInput()}}).}
}
\value{
A text input control that can be added to a UI definition.

View File

@@ -125,6 +125,9 @@ shinyApp(ui, server)
}
}
\seealso{
For more details on how the images are generated, and how to control
\itemize{
\item For more details on how the images are generated, and how to control
the output, see \code{\link[=plotPNG]{plotPNG()}}.
\item Use \code{\link[=outputOptions]{outputOptions()}} to set general output options for an image output.
}
}

View File

@@ -126,3 +126,6 @@ vecFun()
})
}
\seealso{
\code{\link[=outputOptions]{outputOptions()}}
}

View File

@@ -52,5 +52,5 @@ shinyApp(ui, server)
}
\seealso{
\code{\link[=uiOutput]{uiOutput()}}
\code{\link[=uiOutput]{uiOutput()}}, \code{\link[=outputOptions]{outputOptions()}}
}

View File

@@ -61,7 +61,7 @@ Other contributors:
\item John Fraser (showdown.js library) [contributor, copyright holder]
\item John Gruber (showdown.js library) [contributor, copyright holder]
\item Ivan Sagalaev (highlight.js library) [contributor, copyright holder]
\item R Core Team (tar implementation from R) [contributor, copyright holder]
\item R Core Team (tar implementation from R) [contributor, copyright holder]
}
}

View File

@@ -44,16 +44,20 @@ have the extensions: r, htm, html, js, css, png, jpg, jpeg, gif. If any
changes are detected, all connected Shiny sessions are reloaded. This
allows for fast feedback loops when tweaking Shiny UI.
Since monitoring for changes is expensive (we simply poll for last
modified times), this feature is intended only for development.
Monitoring for changes is no longer expensive, thanks to the \pkg{watcher}
package, but this feature is still intended only for development.
You can customize the file patterns Shiny will monitor by setting the
shiny.autoreload.pattern option. For example, to monitor only ui.R:
\code{options(shiny.autoreload.pattern = glob2rx("ui.R"))}
shiny.autoreload.pattern option. For example, to monitor only \code{ui.R}:
\code{options(shiny.autoreload.pattern = glob2rx("ui.R"))}.
The default polling interval is 500 milliseconds. You can change this
by setting e.g. \code{options(shiny.autoreload.interval = 2000)} (every
two seconds).}
As mentioned above, Shiny no longer polls watched files for changes.
Instead, using \pkg{watcher}, Shiny is notified of file changes as they
occur. These changes are batched together within a customizable latency
period. You can adjust this period by setting
\code{options(shiny.autoreload.interval = 2000)} (in milliseconds). This value
converted to seconds and passed to the \code{latency} argument of
\code{\link[watcher:watcher]{watcher::watcher()}}. The default latency is 250ms.}
\item{shiny.deprecation.messages (defaults to \code{TRUE})}{This controls whether messages for
deprecated functions in Shiny will be printed. See
\code{\link[=shinyDeprecated]{shinyDeprecated()}} for more information.}
@@ -68,7 +72,7 @@ be done 100\% correctly.}
\code{\link[=runApp]{runApp()}} for more information.}
\item{shiny.jquery.version (defaults to \code{3})}{The major version of jQuery to use.
Currently only values of \code{3} or \code{1} are supported. If \code{1}, then jQuery 1.12.4 is used. If \code{3},
then jQuery 3.6.0 is used.}
then jQuery 3.7.1 is used.}
\item{shiny.json.digits (defaults to \code{I(16)})}{Max number of digits to use when converting
numbers to JSON format to send to the client web browser. Use \code{\link[=I]{I()}} to specify significant digits.
Use \code{NA} for max precision.}

View File

@@ -13,7 +13,10 @@ textAreaInput(
cols = NULL,
rows = NULL,
placeholder = NULL,
resize = NULL
resize = NULL,
...,
autoresize = FALSE,
updateOn = c("change", "blur")
)
}
\arguments{
@@ -46,6 +49,19 @@ option.}
\item{resize}{Which directions the textarea box can be resized. Can be one of
\code{"both"}, \code{"none"}, \code{"vertical"}, and \code{"horizontal"}. The default, \code{NULL},
will use the client browser's default setting for resizing textareas.}
\item{...}{Ignored, included to require named arguments and for future
feature expansion.}
\item{autoresize}{If \code{TRUE}, the textarea will automatically resize to fit
the input text.}
\item{updateOn}{A character vector specifying when the input should be
updated. Options are \code{"change"} (default) and \code{"blur"}. Use \code{"change"} to
update the input immediately whenever the value changes. Use \code{"blur"}to
delay the input update until the input loses focus (the user moves away
from the input), or when Enter is pressed (or Cmd/Ctrl + Enter for
\code{\link[=textAreaInput]{textAreaInput()}}).}
}
\value{
A textarea input control that can be added to a UI definition.

View File

@@ -4,7 +4,15 @@
\alias{textInput}
\title{Create a text input control}
\usage{
textInput(inputId, label, value = "", width = NULL, placeholder = NULL)
textInput(
inputId,
label,
value = "",
width = NULL,
placeholder = NULL,
...,
updateOn = c("change", "blur")
)
}
\arguments{
\item{inputId}{The \code{input} slot that will be used to access the value.}
@@ -19,6 +27,16 @@ see \code{\link[=validateCssUnit]{validateCssUnit()}}.}
\item{placeholder}{A character string giving the user a hint as to what can
be entered into the control. Internet Explorer 8 and 9 do not support this
option.}
\item{...}{Ignored, included to require named arguments and for future
feature expansion.}
\item{updateOn}{A character vector specifying when the input should be
updated. Options are \code{"change"} (default) and \code{"blur"}. Use \code{"change"} to
update the input immediately whenever the value changes. Use \code{"blur"}to
delay the input update until the input loses focus (the user moves away
from the input), or when Enter is pressed (or Cmd/Ctrl + Enter for
\code{\link[=textAreaInput]{textAreaInput()}}).}
}
\value{
A text input control that can be added to a UI definition.

View File

@@ -3,7 +3,7 @@
"homepage": "https://shiny.rstudio.com",
"repository": "github:rstudio/shiny",
"name": "@types/rstudio-shiny",
"version": "1.10.0-alpha.9000",
"version": "1.11.0",
"license": "GPL-3.0-only",
"main": "",
"browser": "",
@@ -23,16 +23,11 @@
"@types/bootstrap-datepicker": "0.0.14",
"@types/datatables.net": "^1.10.19",
"@types/ion-rangeslider": "2.3.0",
"@types/jquery": "3.5.14",
"@types/jquery": "3.5.32",
"@types/selectize": "0.12.34",
"lit": "^3.0.0"
},
"devDependencies": {
"@babel/core": "^7.14.3",
"@babel/plugin-proposal-class-properties": "^7.13.0",
"@babel/preset-env": "^7.14.2",
"@babel/preset-typescript": "^7.13.0",
"@babel/runtime": "^7.14.0",
"@deanc/esbuild-plugin-postcss": "^1.0.2",
"@selectize/selectize": "https://github.com/selectize/selectize.js.git#e3f2e0b4aa251375bc21b5fcd8ca7d374a921f08",
"@testing-library/dom": "^7.31.0",
@@ -40,7 +35,7 @@
"@testing-library/user-event": "^13.1.9",
"@types/highlightjs": "^9.12.1",
"@types/jest": "^26.0.23",
"@types/jqueryui": "1.12.16",
"@types/jqueryui": "1.12.24",
"@types/lodash": "^4.14.170",
"@types/node": "^18.14.2",
"@types/showdown": "^1.9.3",
@@ -51,7 +46,6 @@
"caniuse-lite": "^1.0.30001312",
"core-js": "^3.13.0",
"esbuild": "^0.15.10",
"esbuild-plugin-babel": "https://github.com/schloerke/esbuild-plugin-babel#patch-2",
"esbuild-plugin-globals": "^0.1.1",
"esbuild-plugin-sass": "^1.0.1",
"eslint": "^8.24.0",
@@ -62,7 +56,7 @@
"eslint-plugin-unicorn": "^43.0.2",
"fs-readdir-recursive": "^1.1.0",
"jest": "^26.6.3",
"jquery": "^3.6.0",
"jquery": "3.7.1",
"lodash": "^4.17.21",
"madge": "^4.0.2",
"node-gyp": "^8.1.0",

View File

@@ -1,34 +1,28 @@
# Revdeps
## Failed to check (20)
|package |version |error |warning |note |
|:------------------|:-------|:-----|:-------|:----|
|animalEKF |1.2 |1 | | |
|AovBay |0.1.0 |1 | | |
|Certara.VPCResults |3.0.2 |1 | | |
|chipPCR |1.0-2 |1 | | |
|ctsem |3.10.1 |1 | | |
|dartR.sim |? | | | |
|diveR |? | | | |
|gap |? | | | |
|jsmodule |? | | | |
|loon.shiny |? | | | |
|robmedExtra |0.1.1 |1 | | |
|rstanarm |2.32.1 |1 | | |
|SensMap |0.7 |1 | | |
|Seurat |5.1.0 |1 | |1 |
|shinyTempSignal |0.0.8 |1 | | |
|Signac |1.14.0 |1 | | |
|statsr |0.3.0 |1 | | |
|TestAnaAPP |1.1.2 |1 | | |
|tidyvpc |1.5.2 |1 | | |
|visR |? | | | |
## New problems (2)
|package |version |error |warning |note |
|:-------|:-------|:-----|:-------|:------|
|[HH](problems.md#hh)|3.1-52 | | |__+1__ |
|[PopED](problems.md#poped)|0.7.0 | | |__+1__ |
## Failed to check (22)
|package |version |error |warning |note |
|:--------------------|:-------|:-----|:-------|:----|
|bigPint |? | | | |
|bioCancer |? | | | |
|EBImage |? | | | |
|FAfA |0.3 |1 | | |
|fio |0.1.6 |1 | | |
|GeneNetworkBuilder |? | | | |
|gradientPickerD3 |? | | | |
|InterCellar |? | | | |
|LACE |? | | | |
|lavaan.shiny |1.2 |1 | | |
|LDABiplots |? | | | |
|LDAShiny |? | | | |
|loon.shiny |? | | | |
|MatrixQCvis |? | | | |
|metricsgraphics |? | | | |
|modchart |? | | | |
|omicsViewer |? | | | |
|RSP |0.4 |1 | | |
|rstanarm |2.32.1 |1 | | |
|sphereML |0.1.1 |1 | | |
|StatTeacherAssistant |? | | | |
|TestAnaAPP |1.1.2 |1 | | |

View File

@@ -1,39 +1,19 @@
## revdepcheck results
We checked 1278 reverse dependencies (1277 from CRAN + 1 from Bioconductor), comparing R CMD check results across CRAN and dev versions of this package.
We checked 1344 reverse dependencies (1330 from CRAN + 14 from Bioconductor), comparing R CMD check results across CRAN and dev versions of this package.
* We saw 2 new problems
* We failed to check 19 packages
* We saw 0 new problems
* We failed to check 8 packages
Issues with CRAN packages are summarised below.
### New problems
(This reports the first line of each new failure)
* HH
checking installed package size ... NOTE
* PopED
checking installed package size ... NOTE
### Failed to check
* animalEKF (NA)
* AovBay (NA)
* Certara.VPCResults (NA)
* chipPCR (NA)
* ctsem (NA)
* dartR.sim (NA)
* diveR (NA)
* gap (NA)
* jsmodule (NA)
* loon.shiny (NA)
* robmedExtra (NA)
* rstanarm (NA)
* SensMap (NA)
* Seurat (NA)
* shinyTempSignal (NA)
* Signac (NA)
* statsr (NA)
* TestAnaAPP (NA)
* tidyvpc (NA)
* FAfA (NA)
* fio (NA)
* lavaan.shiny (NA)
* loon.shiny (NA)
* RSP (NA)
* rstanarm (NA)
* sphereML (NA)
* TestAnaAPP (NA)

View File

@@ -1,49 +1 @@
# HH
<details>
* Version: 3.1-52
* GitHub: NA
* Source code: https://github.com/cran/HH
* Date/Publication: 2024-02-11 00:00:02 UTC
* Number of recursive dependencies: 165
Run `revdepcheck::cloud_details(, "HH")` for more info
</details>
## Newly broken
* checking installed package size ... NOTE
```
installed size is 5.1Mb
sub-directories of 1Mb or more:
R 1.5Mb
help 1.5Mb
```
# PopED
<details>
* Version: 0.7.0
* GitHub: https://github.com/andrewhooker/PopED
* Source code: https://github.com/cran/PopED
* Date/Publication: 2024-10-07 19:30:02 UTC
* Number of recursive dependencies: 140
Run `revdepcheck::cloud_details(, "PopED")` for more info
</details>
## Newly broken
* checking installed package size ... NOTE
```
installed size is 5.5Mb
sub-directories of 1Mb or more:
R 1.5Mb
doc 1.4Mb
test 1.1Mb
```
*Wow, no problems at all. :)*

View File

@@ -150,12 +150,6 @@ All config files are located in the root folder to avoid opening two separate VS
* Used by `prettier` to know how to adjust code when a file is saved in VSCode or within `eslint`'s linting process.
* `yarnrc.yml`
* Notifies `yarn` to use `yarn` v2, install `./node_modules` folder for `esbuild`, and any CLI plugins.
* `babel.config.json`
* Used within `babel` transpilation of TypeScript -> JavaScript -> polyfilled JavaScript.
* Noteable options set:
* `"useBuiltIns": "usage"` - `core-js` polyfills are only added as they are _used_.
* `"corejs": "3.9"` - This number should match the installed `core-js` number.
* `"ignore":["node_modules/core-js"]` - The `core-js` library is directly ignored to [avoid being processed by `babel`](https://github.com/zloirock/core-js/issues/743#issuecomment-571983318).
* `jest.config.js`
* Used to configure [`jest` testing](https://jestjs.io/)
* `package.json`
@@ -168,7 +162,7 @@ All config files are located in the root folder to avoid opening two separate VS
* `tsconfig.json` -
* TypeScript config file
* Notable options set:
* `target: ES5` - Compile to es5, so babel has an easier job.
* `target: ES2021` - Compile to es2021.
* `preserveConstEnums: false` - Do no preserve enum values into the final code. (If true, produces bloat / unused code)
* `isolatedModules: true` & `esModuleInterop: true` - Requested by `esbuild`. This [allows for `esbuild`](https://esbuild.github.io/content-types/#typescript) to safely compile the files in parallel

View File

@@ -1,108 +0,0 @@
# Development Rules
* Put Imports at top
* Put Exports at bottom
* File / Folder structure
* Lean towards using more many files / folder vs larger files
* Nest folders inside larger _ideas_
* Each folder should generally have an `**/index.ts` to export most everything for the folder
* Exception: `./src/window` folder. Must call methods directly.
* Any `window.***` calls are done in `./src/window` folder only.
* Add exported values / function if necessary.
* This helps keep each file self contained. Trying not to have random inputs from anywhere
* jQuery
* Always import `./src/jquery` instead of `"jquery"`
* Exeption: Test files. There, you can import `"jquery"` directly as the browser is not available to already have jQuery loaded.
* Prevents from installing local jquery in addition to global jquery
* WAY to many packages exist on the assumption that jquery is available at run time. Therefore, it can not be removed globally. :-(
* Anything that needs to be initialized on start **must** exist in the `./src/initialize` folder.
* No file should produce any side effects.
* To capture initializations, export a `setFoo(foo_)` method that updates a locally defined `foo` variable.
# TODO
* √ Move everything into a single ts file. This will allow for the functions to find themselves
* √ Except the utils.js already converted
* √ es6 shiny.js
* √ Pass in version using esbuild
* √ Move all shiny files in order to main.ts
* √ validate polyfills are working by finding them in the code
* √ Produce minified shiny js
* √ Disable $ from being found without an import
* √ Using a patch with yarn v2
* √ Document `./package.json` scripts
* √ Verify that `babel` is configurable
* √ Use targeting browsers
* √ Verify it works on phantomjs / shinytest
* √ Set up initial jest tests
* √ Use a global shim to avoid importing jquery directly, but make testing easy to test
* Update the /tools/update*.R scripts to produce a version and install node dependencies
* √ jquery
* √ ion range slider
* √ selectize
* √ strftime
* √ bootstrap date picker
* font awesome?
* bootstrap accessibility plugin?
# Round #2
* Convert registered bindings
* √ Input bindings
* √ Output bindings
* Add default value to `subscribe(callback)` callback function of `false`. B/c if the value was not provided, it was not truthy, therefore equivalent to `false`.
* √ radio
* √ checkboxgroup
* √ daterange
* √ actionbutton
* √ bootstraptabinput
* √ snake_case to camelCase conversions.
* √ globally import strftime from `window.strftime`
* Remove `evt` from jQuery.on callbacks where `evt` was not used.
* √ checkbox.subscribe
* √ checkboxgroup.subscribe
* √ radio.subscribe
* √ slider.subscribe
* √ date.subscribe
* √ selectInput.subscribe
* √ actionButton.subscribe
* √ bootstraptabinput.subscribe
* Convert usage of `+x` to `Number(x)`
* https://stackoverflow.com/a/15872631/591574
* √ slider.getValue()
* √ number.getValue()
* √ Adjust tabinput.ts `setValue()` to return either `false | void`, not `false | true`.
* What matters is that `false` is returned, or nothing is returned. Replaced `return true;` with `return;`
* Questions
* Why does `receiveMessage(data)` sometimes have a `label`?
* Should we have a update datatables script?
# Later TODO
* Use --strictNullChecks in tsconfig.json
* Make `_*()` methods `private *()`
* √ Each _file_ will be pulled out as possible into smaller files in separate PRs
* √ Convert `FileProcessor` to a true class definition
* Break up `./utils` into many files
* √ Remove any `: any` types
* √ Make `@typescript-eslint/explicit-module-boundary-types` an error
* √ Fix all `// eslint-disable-next-line no-prototype-builtins` lines
* TypeScript other shiny files (ex: showcasemode)
* √ Completely remove `parcel` from `./package.json` and only use `esbuild`
* √ Delete 'shiny-es5' files
* Delete 'old' folder
* _Uglify_ js files (like in previous Gruntfile.js)
* datepicker
* ionrangeslider
* selectize
# Eventual TODO
* Use yarn PnP
* See `./patch/yarn_pnp.patch`
* Use [esbuild](https://github.com/yarnpkg/berry/tree/master/packages/esbuild-plugin-pnp#yarnpkgesbuild-plugin-pnp)
* Known problems:
* `@yarnpkg/esbuild-plugin-pnp@0.0.1` gives full file paths, not relative file paths
* `@testing-library/jest-dom/extend-expect` can not be found.

View File

@@ -14,10 +14,6 @@ import process from "process";
// @ts-ignore; Type definitions are not found. This occurs when `strict: true` in tsconfig.json
import readcontrol from "readcontrol";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore; Type definitions are not found. This occurs when `strict: true` in tsconfig.json
import babelPlugin from "esbuild-plugin-babel";
const outDir = "./inst/www/shared/";
type ShinyDesc = { version: string; package: string; license: string };
@@ -79,7 +75,7 @@ async function build(
return esbuildBuild({
incremental: incremental,
watch: watch,
target: "es5",
target: "es2021",
preserveSymlinks: true,
...opts,
}).then((x) => {
@@ -88,4 +84,4 @@ async function build(
});
}
export { outDir, build, shinyDesc, banner, babelPlugin };
export { outDir, build, shinyDesc, banner };

View File

@@ -5,13 +5,13 @@
// - TypeScript -----------------------------------------------------------
import { banner, build, outDir, babelPlugin } from "./_build";
import { banner, build, outDir } from "./_build";
build({
bundle: true,
sourcemap: true,
minify: true,
plugins: [babelPlugin()],
plugins: [],
banner: banner,
entryPoints: [
"srcts/extras/shiny-autoreload.ts",

View File

@@ -3,9 +3,9 @@
// yarn build
// ```
import { banner, build, outDir, shinyDesc, babelPlugin } from "./_build";
import globalsPlugin from "esbuild-plugin-globals";
import type { BuildOptions } from "esbuild";
import globalsPlugin from "esbuild-plugin-globals";
import { banner, build, outDir, shinyDesc } from "./_build";
import { verifyJqueryImport } from "./_jquery";
const opts: BuildOptions = {
@@ -18,7 +18,6 @@ const opts: BuildOptions = {
//// Loaded dynamically. MUST use `window.strftime` within code
// strftime: "window.strftime",
}),
babelPlugin(),
],
define: {
// eslint-disable-next-line @typescript-eslint/naming-convention

View File

@@ -7,6 +7,8 @@
.recalculating {
min-height: var(--shiny-spinner-size, 32px);
&::after {
position: absolute;
content: "";
@@ -45,13 +47,31 @@
transition: opacity 250ms ease var(--shiny-spinner-delay, 1s);
}
/*
When htmlwidget errors are rendered, an inline `visibility:hidden` is put
on the html-widget-output, and the error message (if any) is put in a
sibling element that overlays the output container (this way, the height
of the output container doesn't change). Work around this by making the
output container itself visible and making the children (except the
spinner) invisible.
*/
&.html-widget-output {
visibility: inherit !important;
> * {
visibility: hidden;
}
::after {
visibility: visible;
}
}
/*
Disable spinner on uiOutput() mainly because (for other reasons) it has
`display:contents`, which breaks the ::after positioning.
Note that, even if we could position it, we'd probably want to disable it
if it has recalculating children.
*/
&.shiny-html-output::after {
&.shiny-html-output:not(.shiny-table-output)::after {
display: none;
}
}
@@ -105,6 +125,9 @@
&.shiny-busy:has(.recalculating:not(.shiny-html-output))::after {
display: none;
}
&.shiny-busy:has(.recalculating.shiny-table-output)::after {
display: none;
}
&.shiny-busy:has(#shiny-disconnected-overlay)::after {
display: none;
}

View File

@@ -1,9 +0,0 @@
# `yarn` Patch files
* `yarn_pnp.patch`
* This file is currently not used and is outdated.
* This provides a good game plan on how to use PnP with Yarn once esbuild can easily be integrated with Yarn PnP.
* Using PnP removes the `node_modules` folder, but adds a zip of each package. I **do not** like Yarn's suggestion to commit these zip files to support their [Zero Installs](https://next.yarnpkg.com/features/zero-installs) philosophy.
* Reference:
* https://next.yarnpkg.com/features/pnp
* https://yarnpkg.com/api/modules/esbuild_plugin_pnp.html

View File

@@ -1,250 +0,0 @@
diff --git a/srcts/TODO.md b/srcts/TODO.md
index dbe275f1..e36ced9e 100644
--- a/srcts/TODO.md
+++ b/srcts/TODO.md
@@ -36,6 +36,7 @@
* √ Verify it works on phantomjs / shinytest
* √ Set up initial jest tests
* √ Use a global shim to avoid importing jquery directly, but make testing easy to test
+* √ Use yarn PnP
# Later TODO
@@ -49,12 +50,3 @@
* Completely remove `parcel` from `./package.json` and only use `esbuild`
* Delete 'shiny-es5' files
* Delete 'old' folder
-
-
-# Eventual TODO
-* Use yarn PnP
- * Use [esbuild](https://github.com/yarnpkg/berry/tree/master/packages/esbuild-plugin-pnp#yarnpkgesbuild-plugin-pnp)
- * Remove `./.yarnrc.yaml` `nodeLinker` key
- * TODO - Figure out how to call the esbuild command with the missing packages. Currently Yarn can't ifnd `esbuild` and suggests `esbuild-X.Y.Z-SHA` (or something other than `esbuild`) which does not make sense.
- * Calling `yarn node esbuild.config.mjs` does not work
- * Calling `yarn pnpify node esbuild.config.mjs` does not work
diff --git a/srcts/esbuild.config.js b/srcts/esbuild.config.js
new file mode 100644
index 00000000..8e4a0801
--- /dev/null
+++ b/srcts/esbuild.config.js
@@ -0,0 +1,54 @@
+/* eslint-disable no-undef */
+/* eslint-disable @typescript-eslint/no-var-requires */
+
+// !! Do not convert this file to a module (aka using `import` statements) as VSCode suggests to do
+// Yarn shims the `require` function to make PnP work. It does not work on import statements
+
+const esbuild = require("esbuild");
+const babel = require("esbuild-plugin-babel");
+const readcontrol = require("readcontrol");
+const pnpPlugin = require("esbuild-plugin-pnp");
+const process = require("process");
+const globalsPlugin = require("esbuild-plugin-globals");
+
+let watch = process.argv.length >= 3 && process.argv[2] == "--watch";
+
+let outdir = "../inst/www/shared/";
+let opts = {
+ entryPoints: ["src/index.ts"],
+ bundle: true,
+ watch: watch,
+ plugins: [
+ globalsPlugin({
+ jquery: "window.jQuery",
+ }),
+ pnpPlugin(),
+ babel(),
+ ],
+ target: "es5",
+ sourcemap: true,
+ define: {
+ "process.env.SHINY_VERSION": `"${
+ readcontrol.readSync("../DESCRIPTION").version
+ }"`,
+ },
+};
+
+console.log("Building shiny.js");
+esbuild
+ .build({
+ ...opts,
+ outfile: outdir + "shiny.js",
+ })
+ .then(() => {
+ console.log("Building shiny.min.js");
+ esbuild.build({
+ ...opts,
+ outfile: outdir + "shiny.min.js",
+ minify: true,
+ });
+ })
+ .catch((reason) => {
+ console.error(reason);
+ process.exit(1);
+ });
diff --git a/srcts/esbuild.config.mjs b/srcts/esbuild.config.mjs
deleted file mode 100644
index ffdb855b..00000000
--- a/srcts/esbuild.config.mjs
+++ /dev/null
@@ -1,40 +0,0 @@
-import esbuild from "esbuild";
-import babel from "esbuild-plugin-babel";
-import readcontrol from "readcontrol";
-import process from "process";
-import globalsPlugin from "esbuild-plugin-globals";
-
-let watch = process.argv.length >= 3 && process.argv[2] == "--watch";
-
-let outdir = "../inst/www/shared/";
-let opts = {
- entryPoints: ["src/index.ts"],
- bundle: true,
- watch: watch,
- plugins: [
- globalsPlugin({
- jquery: "window.jQuery",
- }),
- babel(),
- ],
- target: "es5",
- sourcemap: true,
- define: {
- "process.env.SHINY_VERSION": `"${
- readcontrol.readSync("../DESCRIPTION").version
- }"`,
- },
-};
-
-console.log("Building shiny.js");
-await esbuild.build({
- ...opts,
- outfile: outdir + "shiny.js",
-});
-
-console.log("Building shiny.min.js");
-await esbuild.build({
- ...opts,
- outfile: outdir + "shiny.min.js",
- minify: true,
-});
diff --git a/srcts/package.json b/srcts/package.json
index c7f6b66b..edff5ce9 100644
--- a/srcts/package.json
+++ b/srcts/package.json
@@ -21,8 +21,9 @@
"@typescript-eslint/parser": "^4",
"browserslist": "^4.16.3",
"esbuild": "^0.8.50",
- "esbuild-plugin-babel": "0.2.3",
+ "esbuild-plugin-babel": "patch:esbuild-plugin-babel@0.2.3#./patch/esbuild-plugin-babel.patch",
"esbuild-plugin-globals": "^0.1.1",
+ "esbuild-plugin-pnp": "^0.3.0",
"eslint": "^7",
"eslint-config-prettier": "^7",
"eslint-plugin-jest": "^24",
@@ -45,7 +46,7 @@
"build": "yarn run build_shiny",
"setup_build_shiny": "yarn run lint && yarn run typescript-check",
"build_shiny": "yarn run setup_build_shiny && yarn run bundle_shiny",
- "bundle_shiny": "node esbuild.config.mjs",
+ "bundle_shiny": "node esbuild.config.js",
"bundle_shiny_parcel2": "parcel build -d ../inst/www/shared --no-minify -o shiny.js src/index.ts",
"watch_parcel2": "yarn run setup_build_shiny && parcel run -d ../inst/www/shared -o shiny.js srcjs/index.ts",
"replace_shiny_version2": "replace --silent '\"[^\"]+\"; // @VERSION@' \"\\\"`node -e 'console.log(require(\"readcontrol\").readSync(\"../DESCRIPTION\").version)'`\\\"; // @VERSION@\" src/shiny.ts",
diff --git a/srcts/patch/esbuild-plugin-babel.patch b/srcts/patch/esbuild-plugin-babel.patch
new file mode 100644
index 00000000..24cc9425
--- /dev/null
+++ b/srcts/patch/esbuild-plugin-babel.patch
@@ -0,0 +1,33 @@
+diff --git a/package.json b/package.json
+index 6b9cdb89e2bbf0f5b5ad65adb53951d129f265ca..4e9b0e08e1c9850ff637eb6a47b5f3cfa33bbb55 100644
+--- a/package.json
++++ b/package.json
+@@ -7,7 +7,6 @@
+ "license": "ISC",
+ "exports": "./src/index.js",
+ "main": "src/index.js",
+- "type": "module",
+ "scripts": {
+ "format": "prettier --write --ignore-unknown '**/*'"
+ },
+diff --git a/src/index.js b/src/index.js
+index b3cff90a292daa6cfac0566ee73bab142ac627df..d06ecf8873a45a5ea3cda7edb3814e8034efed32 100644
+--- a/src/index.js
++++ b/src/index.js
+@@ -1,6 +1,7 @@
+-import babel from '@babel/core';
+-import fs from 'fs';
+-import path from 'path';
++const babel = require('@babel/core');
++const fs = require('fs');
++const path = require('path');
++
+
+ const pluginBabel = (options = {}) => ({
+ name: 'babel',
+@@ -41,4 +42,4 @@ const pluginBabel = (options = {}) => ({
+ }
+ });
+
+-export default pluginBabel;
++module.exports = pluginBabel;
diff --git a/srcts/yarn.lock b/srcts/yarn.lock
index 90d3fd04..1ca29eba 100644
--- a/srcts/yarn.lock
+++ b/srcts/yarn.lock
@@ -4334,7 +4334,7 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-plugin-babel@npm:0.2.3":
+esbuild-plugin-babel@0.2.3:
version: 0.2.3
resolution: "esbuild-plugin-babel@npm:0.2.3"
peerDependencies:
@@ -4343,6 +4343,15 @@ __metadata:
languageName: node
linkType: hard
+"esbuild-plugin-babel@patch:esbuild-plugin-babel@0.2.3#./patch/esbuild-plugin-babel.patch::locator=root-workspace-0b6124%40workspace%3A.":
+ version: 0.2.3
+ resolution: "esbuild-plugin-babel@patch:esbuild-plugin-babel@npm%3A0.2.3#./patch/esbuild-plugin-babel.patch::version=0.2.3&hash=80b9d8&locator=root-workspace-0b6124%40workspace%3A."
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: 91e0a233ed255b4798b3a1d9b2d9fbc8ea3c107561c69b31790f02c556a4687770a13d2b4c58f3dc638198bcddd5c6d7d26496a6578da730cd635dea1dd8450c
+ languageName: node
+ linkType: hard
+
"esbuild-plugin-globals@npm:^0.1.1":
version: 0.1.1
resolution: "esbuild-plugin-globals@npm:0.1.1"
@@ -4350,6 +4359,15 @@ __metadata:
languageName: node
linkType: hard
+"esbuild-plugin-pnp@npm:^0.3.0":
+ version: 0.3.0
+ resolution: "esbuild-plugin-pnp@npm:0.3.0"
+ peerDependencies:
+ esbuild: ^0.8.1
+ checksum: b80ab17bea35ab6eaf9a9adc14c52667c0a5e2c7c8c8e97194c57feb7d14b7247228745a3ad34f69447d6c5241081f38b9786948b879bf0051a479ce74450edc
+ languageName: node
+ linkType: hard
+
"esbuild@npm:^0.8.50":
version: 0.8.50
resolution: "esbuild@npm:0.8.50"
@@ -9295,8 +9313,9 @@ fsevents@^2.1.2:
browserslist: ^4.16.3
core-js: ^3.9
esbuild: ^0.8.50
- esbuild-plugin-babel: 0.2.3
+ esbuild-plugin-babel: "patch:esbuild-plugin-babel@0.2.3#./patch/esbuild-plugin-babel.patch"
esbuild-plugin-globals: ^0.1.1
+ esbuild-plugin-pnp: ^0.3.0
eslint: ^7
eslint-config-prettier: ^7
eslint-plugin-jest: ^24

View File

@@ -1,11 +1,16 @@
import $ from "jquery";
import type { HtmlDep } from "../../shiny/render";
import { renderContent } from "../../shiny/render";
import { hasDefinedProperty } from "../../utils";
import { InputBinding } from "./inputBinding";
type CheckedHTMLElement = HTMLInputElement;
type CheckboxChecked = CheckedHTMLElement["checked"];
type CheckboxReceiveMessageData = { value?: CheckboxChecked; label?: string };
type CheckboxReceiveMessageData = {
value?: CheckboxChecked;
label?: { html: string; deps: HtmlDep[] };
};
class CheckboxInputBinding extends InputBinding {
find(scope: HTMLElement): JQuery<HTMLElement> {
@@ -32,10 +37,10 @@ class CheckboxInputBinding extends InputBinding {
value: el.checked,
};
}
receiveMessage(
async receiveMessage(
el: CheckedHTMLElement,
data: CheckboxReceiveMessageData
): void {
): Promise<void> {
if (hasDefinedProperty(data, "value")) {
el.checked = data.value;
}
@@ -43,7 +48,8 @@ class CheckboxInputBinding extends InputBinding {
// checkboxInput()'s label works different from other
// input labels...the label container should always exist
if (hasDefinedProperty(data, "label")) {
$(el).parent().find("span").text(data.label);
const labelSpan = $(el).parent().find("span");
await renderContent(labelSpan, data.label);
}
$(el).trigger("change");

View File

@@ -113,10 +113,10 @@ class CheckboxGroupInputBinding extends InputBinding {
options: options,
};
}
receiveMessage(
async receiveMessage(
el: CheckboxGroupHTMLElement,
data: CheckboxGroupReceiveMessageData
): void {
): Promise<void> {
const $el = $(el);
// This will replace all the options
@@ -132,7 +132,7 @@ class CheckboxGroupInputBinding extends InputBinding {
this.setValue(el, data.value);
}
updateLabel(data.label, getLabelNode(el));
await updateLabel(data.label, getLabelNode(el));
$(el).trigger("change");
}

View File

@@ -292,10 +292,13 @@ class DateInputBinding extends DateInputBindingBase {
startview: startview,
};
}
receiveMessage(el: HTMLElement, data: DateReceiveMessageData): void {
async receiveMessage(
el: HTMLElement,
data: DateReceiveMessageData
): Promise<void> {
const $input = $(el).find("input");
updateLabel(data.label, this._getLabelNode(el));
await updateLabel(data.label, this._getLabelNode(el));
if (hasDefinedProperty(data, "min")) this._setMin($input[0], data.min);

View File

@@ -106,13 +106,16 @@ class DateRangeInputBinding extends DateInputBindingBase {
startview: startview,
};
}
receiveMessage(el: HTMLElement, data: DateRangeReceiveMessageData): void {
async receiveMessage(
el: HTMLElement,
data: DateRangeReceiveMessageData
): Promise<void> {
const $el = $(el);
const $inputs = $el.find("input");
const $startinput = $inputs.eq(0);
const $endinput = $inputs.eq(1);
updateLabel(data.label, getLabelNode(el));
await updateLabel(data.label, getLabelNode(el));
if (hasDefinedProperty(data, "min")) {
this._setMin($startinput[0], data.min);

View File

@@ -1,6 +1,22 @@
import type { EventPriority } from "../../inputPolicies/inputPolicy";
import type { RatePolicyModes } from "../../inputPolicies/inputRateDecorator";
import type { BindScope } from "../../shiny/bind";
type SubscribeEventPriority =
| EventPriority
| boolean
| { priority: EventPriority };
// Historically, the .subscribe()'s callback value only took a boolean. In this
// case:
// * false: send value immediately (i.e., priority = "immediate")
// * true: send value later (i.e., priority = "deferred")
// * The input rate policy is also consulted on whether to debounce or
// throttle
// In recent versions, the value can also be "event", meaning that the
// value should be sent immediately regardless of whether it has changed.
type InputSubscribeCallback = (value: SubscribeEventPriority) => void;
class InputBinding {
name!: string;
@@ -26,10 +42,7 @@ class InputBinding {
el; // unused var
}
// The callback method takes one argument, whose value is boolean. If true,
// allow deferred (debounce or throttle) sending depending on the value of
// getRatePolicy. If false, send value immediately. Default behavior is `false`
subscribe(el: HTMLElement, callback: (value: boolean) => void): void {
subscribe(el: HTMLElement, callback: InputSubscribeCallback): void {
// empty
el; // unused var
callback; // unused var
@@ -102,3 +115,4 @@ class InputBinding {
//// END NOTES FOR FUTURE DEV
export { InputBinding };
export type { InputSubscribeCallback, SubscribeEventPriority };

View File

@@ -51,7 +51,10 @@ class NumberInputBinding extends TextInputBindingBase {
return "shiny.number";
el;
}
receiveMessage(el: NumberHTMLElement, data: NumberReceiveMessageData): void {
async receiveMessage(
el: NumberHTMLElement,
data: NumberReceiveMessageData
): Promise<void> {
// Setting values to `""` will remove the attribute value from the DOM element.
// The attr key will still remain, but there is not value... ex: `<input id="foo" type="number" min max/>`
if (hasDefinedProperty(data, "value")) el.value = data.value ?? "";
@@ -59,7 +62,7 @@ class NumberInputBinding extends TextInputBindingBase {
if (hasDefinedProperty(data, "max")) el.max = data.max ?? "";
if (hasDefinedProperty(data, "step")) el.step = data.step ?? "";
updateLabel(data.label, getLabelNode(el));
await updateLabel(data.label, getLabelNode(el));
$(el).trigger("change");
}

View File

@@ -103,7 +103,10 @@ class RadioInputBinding extends InputBinding {
options: options,
};
}
receiveMessage(el: RadioHTMLElement, data: RadioReceiveMessageData): void {
async receiveMessage(
el: RadioHTMLElement,
data: RadioReceiveMessageData
): Promise<void> {
const $el = $(el);
// This will replace all the options
@@ -122,7 +125,7 @@ class RadioInputBinding extends InputBinding {
this.setValue(el, data.value);
}
updateLabel(data.label, getLabelNode(el));
await updateLabel(data.label, getLabelNode(el));
$(el).trigger("change");
}

View File

@@ -102,10 +102,10 @@ class SelectInputBinding extends InputBinding {
options: options,
};
}
receiveMessage(
async receiveMessage(
el: SelectHTMLElement,
data: SelectInputReceiveMessageData
): void {
): Promise<void> {
const $el = $(el);
// This will replace all the options
@@ -205,7 +205,7 @@ class SelectInputBinding extends InputBinding {
this.setValue(el, data.value);
}
updateLabel(data.label, getLabelNode(el));
await updateLabel(data.label, getLabelNode(el));
$(el).trigger("change");
}

View File

@@ -179,7 +179,10 @@ class SliderInputBinding extends TextInputBindingBase {
unsubscribe(el: HTMLElement): void {
$(el).off(".sliderInputBinding");
}
receiveMessage(el: HTMLElement, data: SliderReceiveMessageData): void {
async receiveMessage(
el: HTMLElement,
data: SliderReceiveMessageData
): Promise<void> {
const $el = $(el);
const slider = $el.data("ionRangeSlider");
const msg: {
@@ -226,7 +229,7 @@ class SliderInputBinding extends TextInputBindingBase {
}
}
updateLabel(data.label, getLabelNode(el));
await updateLabel(data.label, getLabelNode(el));
// (maybe) update data elements
const domElements: Array<"data-type" | "time-format" | "timezone"> = [

View File

@@ -50,21 +50,38 @@ class TextInputBindingBase extends InputBinding {
}
subscribe(el: TextHTMLElement, callback: (x: boolean) => void): void {
$(el).on(
"keyup.textInputBinding input.textInputBinding",
// event: Event
function () {
callback(true);
}
);
$(el).on(
"change.textInputBinding",
// event: Event
function () {
const $el = $(el);
const updateOn = $el.data("update-on") || "change";
if (updateOn === "change") {
$el.on(
"keyup.textInputBinding input.textInputBinding",
// event: Event
function () {
callback(true);
}
);
} else if (updateOn === "blur") {
$el.on("blur.textInputBinding", function () {
callback(false);
});
$el.on("keydown.textInputBinding", function (event: JQuery.Event) {
if (event.key !== "Enter") return;
if ($el.is("textarea")) {
if (!(event.ctrlKey || event.metaKey)) return;
}
callback(false);
});
}
$el.on("change.textInputBinding", function () {
if (updateOn === "blur" && $el.is(":focus")) {
return;
}
);
callback(false);
});
}
unsubscribe(el: TextHTMLElement): void {
$(el).off(".textInputBinding");
}
@@ -109,10 +126,13 @@ class TextInputBinding extends TextInputBindingBase {
placeholder: el.placeholder,
};
}
receiveMessage(el: TextHTMLElement, data: TextReceiveMessageData): void {
async receiveMessage(
el: TextHTMLElement,
data: TextReceiveMessageData
): Promise<void> {
if (hasDefinedProperty(data, "value")) this.setValue(el, data.value);
updateLabel(data.label, getLabelNode(el));
await updateLabel(data.label, getLabelNode(el));
if (hasDefinedProperty(data, "placeholder"))
el.placeholder = data.placeholder;

View File

@@ -2,11 +2,53 @@ import $ from "jquery";
import { TextInputBinding } from "./text";
// When a textarea becomes visible, update the height
const intersectObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
updateHeight(entry.target as HTMLInputElement);
}
});
});
class TextareaInputBinding extends TextInputBinding {
#inputHandler: EventListener | null = null;
find(scope: HTMLElement): JQuery<HTMLElement> {
// Inputs now also have the .shiny-input-textarea class
return $(scope).find("textarea");
}
initialize(el: HTMLInputElement): void {
super.initialize(el);
updateHeight(el);
}
subscribe(el: HTMLInputElement, callback: (x: boolean) => void): void {
super.subscribe(el, callback);
this.#inputHandler = (e) => updateHeight(e.target as HTMLInputElement);
el.addEventListener("input", this.#inputHandler);
intersectObserver.observe(el);
}
unsubscribe(el: HTMLInputElement): void {
super.unsubscribe(el);
if (this.#inputHandler) el.removeEventListener("input", this.#inputHandler);
intersectObserver.unobserve(el);
}
}
function updateHeight(el: HTMLInputElement) {
if (!el.classList.contains("textarea-autoresize")) {
return;
}
if (el.scrollHeight == 0) {
return;
}
el.style.height = "auto";
el.style.height = el.scrollHeight + "px";
}
export { TextareaInputBinding };

View File

@@ -200,6 +200,42 @@ class ShinyErrorConsole extends LitElement {
});
}
static createClientMessageElement({ headline, message }: ShinyClientMessage) {
const msg = document.createElement("shiny-error-message");
msg.setAttribute("headline", headline || "");
msg.setAttribute("message", message);
return msg;
}
appendConsoleMessage({ headline, message }: ShinyClientMessage) {
const content =
this.shadowRoot?.querySelector<HTMLSlotElement>("slot.content");
if (content) {
const nodeKey = (node: Element) => {
const headline = node.getAttribute("headline") || "";
const message = node.getAttribute("message") || "";
return `${headline}::${message}`;
};
const newKey = `${headline}::${message}`;
for (const node of content.assignedElements()) {
if (node.tagName.toLowerCase() === "shiny-error-message") {
if (nodeKey(node) === newKey) {
// Do nothing, this message is already in the console
// TODO: Increase count of message here
return;
}
}
}
}
this.appendChild(
ShinyErrorConsole.createClientMessageElement({ headline, message })
);
return;
}
render() {
return html` <div class="header">
<span class="title"> Shiny Client Errors </span>
@@ -523,17 +559,13 @@ function showShinyClientMessage({
// Check to see if an Error Console Container element already exists. If it
// doesn't we need to add it before putting an error on the screen
let errorConsoleContainer = document.querySelector("shiny-error-console");
if (!errorConsoleContainer) {
errorConsoleContainer = document.createElement("shiny-error-console");
document.body.appendChild(errorConsoleContainer);
let sec = document.querySelector<ShinyErrorConsole>("shiny-error-console");
if (!sec) {
sec = document.createElement("shiny-error-console") as ShinyErrorConsole;
document.body.appendChild(sec);
}
const errorConsole = document.createElement("shiny-error-message");
errorConsole.setAttribute("headline", headline);
errorConsole.setAttribute("message", message);
errorConsoleContainer.appendChild(errorConsole);
sec.appendConsoleMessage({ headline, message });
}
/**

View File

@@ -1,6 +1,7 @@
import $ from "jquery";
import { Shiny } from "..";
import type { InputBinding, OutputBinding } from "../bindings";
import type { SubscribeEventPriority } from "../bindings/input/inputBinding";
import { OutputBindingAdapter } from "../bindings/outputAdapter";
import type { BindingRegistry } from "../bindings/registry";
import { ShinyClientMessageEvent } from "../components/errorConsole";
@@ -8,17 +9,27 @@ import type {
InputRateDecorator,
InputValidateDecorator,
} from "../inputPolicies";
import type { EventPriority } from "../inputPolicies/inputPolicy";
import { shinyAppBindOutput, shinyAppUnbindOutput } from "./initedMethods";
import { sendImageSizeFns } from "./sendImageSize";
type BindScope = HTMLElement | JQuery<HTMLElement>;
/**
* Type guard to check if a value is a jQuery object containing HTMLElements
* @param value The value to check
* @returns A type predicate indicating if the value is a jQuery<HTMLElement>
*/
function isJQuery<T = HTMLElement>(value: unknown): value is JQuery<T> {
return Boolean(value && (value as any).jquery);
}
// todo make sure allowDeferred can NOT be supplied and still work
function valueChangeCallback(
inputs: InputValidateDecorator,
binding: InputBinding,
el: HTMLElement,
allowDeferred: boolean
priority: EventPriority
) {
let id = binding.getId(el);
@@ -28,17 +39,7 @@ function valueChangeCallback(
if (type) id = id + ":" + type;
const opts: {
priority: "deferred" | "immediate";
binding: typeof binding;
el: typeof el;
} = {
priority: allowDeferred ? "deferred" : "immediate",
binding: binding,
el: el,
};
inputs.setInput(id, value, opts);
inputs.setInput(id, value, { priority, binding, el });
}
}
@@ -79,6 +80,10 @@ const bindingsRegistry = (() => {
* otherwise returns an ok status.
*/
function checkValidity(scope: BindScope): void {
if (!isJQuery(scope) && !(scope instanceof HTMLElement)) {
return;
}
type BindingCounts = { [T in BindingTypes]: number };
const duplicateIds = new Map<string, BindingCounts>();
const problems: Set<string> = new Set();
@@ -146,7 +151,7 @@ const bindingsRegistry = (() => {
}:\n${duplicateIdMsg}`;
const event = new ShinyClientMessageEvent({ headline, message });
const scopeElement = scope instanceof HTMLElement ? scope : scope.get(0);
const scopeElement = isJQuery(scope) ? scope.get(0) : scope;
(scopeElement || window).dispatchEvent(event);
}
@@ -259,8 +264,20 @@ function bindInputs(
const thisBinding = binding;
const thisEl = el;
return function (allowDeferred: boolean) {
valueChangeCallback(inputs, thisBinding, thisEl, allowDeferred);
return function (priority: SubscribeEventPriority) {
// Narrow the type of priority to EventPriority
let normalizedPriority: EventPriority;
if (priority === true) {
normalizedPriority = "deferred";
} else if (priority === false) {
normalizedPriority = "immediate";
} else if (typeof priority === "object" && "priority" in priority) {
normalizedPriority = priority.priority;
} else {
normalizedPriority = priority;
}
valueChangeCallback(inputs, thisBinding, thisEl, normalizedPriority);
};
})();

View File

@@ -177,12 +177,12 @@ class ShinyClass {
let target: InputPolicy;
if ($('input[type="submit"], button[type="submit"]').length > 0) {
if (document.querySelector(".shiny-submit-button")) {
// If there is a submit button on the page, use defer decorator
target = inputsDefer;
$('input[type="submit"], button[type="submit"]').each(function () {
$(this).click(function (event) {
document.querySelectorAll(".shiny-submit-button").forEach(function (x) {
x.addEventListener("click", function (event) {
event.preventDefault();
inputsDefer.submit();
});

View File

@@ -18,6 +18,7 @@ import {
getShinyCreateWebsocket,
getShinyOnCustomMessage,
setShinyUser,
shinyBindAll,
shinyForgetLastInputValue,
shinyUnbindAll,
} from "./initedMethods";
@@ -1053,8 +1054,13 @@ class ShinyApp {
const $tabContent = getTabContent($tabset);
let tabsetId = $parentTabset.attr("data-tabsetid");
const $divTag = $(message.divTag.html);
const $liTag = $(message.liTag.html);
// Create a virtual element where we'll temporarily hold the rendered
// nav controls so we can rewrite some attributes and choose where to
// insert the new controls.
const $fragLi = $("<div>");
await renderContentAsync($fragLi, message.liTag, "afterBegin");
const $liTag = $($fragLi).find("> li");
const $aTag = $liTag.find("> a");
// Unless the item is being prepended/appended, the target tab
@@ -1097,13 +1103,16 @@ class ShinyApp {
// text items (which function as dividers and headers inside
// navbarMenus) and whole navbarMenus (since those get
// constructed from scratch on the R side and therefore
// there are no ids that need matching)
// there are no ids that need matching). In other words, we're
// guaranteed to be inserting only one `nav_panel()`.
let fixupDivId = "";
if ($aTag.attr("data-toggle") === "tab") {
const index = getTabIndex($tabset, tabsetId);
const tabId = "tab-" + tabsetId + "-" + index;
$liTag.find("> a").attr("href", "#" + tabId);
$divTag.attr("id", tabId);
// We'll fixup the div ID after we insert it
fixupDivId = tabId;
}
// actually insert the item into the right place
@@ -1120,11 +1129,8 @@ class ShinyApp {
$tabset.append($liTag);
}
}
await shinyBindAll($targetLiTag?.parent() || $tabset);
await renderContentAsync($liTag[0], {
html: $liTag.html(),
deps: message.liTag.deps,
});
// jcheng 2017-07-28: This next part might look a little insane versus the
// more obvious `$tabContent.append($divTag);`, but there's a method to the
// madness.
@@ -1152,40 +1158,30 @@ class ShinyApp {
// In theory the same problem exists for $liTag but since that content is
// much less likely to include arbitrary scripts, we're skipping it.
//
// This code could be nicer if we didn't use renderContent, but rather the
// lower-level functions that renderContent uses. Like if we pre-process
// the value of message.divTag.html for singletons, we could do that, then
// render dependencies, then do $tabContent.append($divTag).
await renderContentAsync(
$tabContent[0],
{ html: "", deps: message.divTag.deps },
// @ts-expect-error; TODO-barret; There is no usage of beforeend
"beforeend"
);
for (const el of $divTag.get()) {
// Must not use jQuery for appending el to the doc, we don't want any
// scripts to run (since they will run when renderContent takes a crack).
$tabContent[0].appendChild(el);
// If `el` itself is a script tag, this approach won't work (the script
// won't be run), since we're only sending innerHTML through renderContent
// and not the whole tag. That's fine in this case because we control the
// R code that generates this HTML, and we know that the element is not
// a script tag.
await renderContentAsync(el, el.innerHTML || el.textContent);
// garrick 2025-01-23: Keeping in mind the above, the `shiny-insert-tab`
// method was re-written to avoid adding the nav controls (liTag) and
// the nav panel contents (divTag) twice. Now, we use
// renderContentAsync() to add both sections to the DOM only once.
await renderContentAsync($tabContent[0], message.divTag, "beforeEnd");
if (fixupDivId) {
// We're inserting one nav_panel() and need to fixup the content ID
$tabContent.find('[id="tab-tsid-id"]').attr("id", fixupDivId);
}
if (message.select) {
$liTag.find("a").tab("show");
}
/* Barbara -- August 2017
Note: until now, the number of tabs in a tabsetPanel (or navbarPage
or navlistPanel) was always fixed. So, an easy way to give an id to
a tab was simply incrementing a counter. (Just like it was easy to
give a random 4-digit number to identify the tabsetPanel). Now that
we're introducing dynamic tabs, we must retrieve these numbers and
fix the dummy id given to the tab in the R side -- there, we always
set the tab id (counter dummy) to "id" and the tabset id to "tsid")
*/
* Note: until now, the number of tabs in a tabsetPanel (or navbarPage
* or navlistPanel) was always fixed. So, an easy way to give an id to
* a tab was simply incrementing a counter. (Just like it was easy to
* give a random 4-digit number to identify the tabsetPanel). Now that
* we're introducing dynamic tabs, we must retrieve these numbers and
* fix the dummy id given to the tab in the R side -- there, we always
* set the tab id (counter dummy) to "id" and the tabset id to "tsid")
*/
function getTabIndex(
$tabset: JQuery<HTMLElement>,
tabsetId: string | undefined

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