Compare commits

..

2 Commits

Author SHA1 Message Date
Carson
0be84710fd Add BS5 support as well 2021-03-23 17:54:14 -05:00
Carson
967078ebbb Quick implementation of switchInput() 2021-03-23 17:29:32 -05:00
41 changed files with 240 additions and 234 deletions

View File

@@ -3,11 +3,11 @@ Type: Package
Title: Web Application Framework for R
Version: 1.6.0.9000
Authors@R: c(
person("Winston", "Chang", role = c("aut", "cre"), email = "winston@rstudio.com", comment = c(ORCID = "0000-0002-1576-2126")),
person("Winston", "Chang", role = c("aut", "cre"), email = "winston@rstudio.com"),
person("Joe", "Cheng", role = "aut", email = "joe@rstudio.com"),
person("JJ", "Allaire", role = "aut", email = "jj@rstudio.com"),
person("Carson", "Sievert", role = "aut", email = "carson@rstudio.com", comment = c(ORCID = "0000-0002-4958-2844")),
person("Barret", "Schloerke", role = "aut", email = "barret@rstudio.com", comment = c(ORCID = "0000-0001-9986-114X")),
person("Carson", "Sievert", role = "aut", email = "carson@rstudio.com"),
person("Barret", "Schloerke", role = "aut", email = "barret@rstudio.com"),
person("Yihui", "Xie", role = "aut", email = "yihui@rstudio.com"),
person("Jeff", "Allen", role = "aut", email = "jeff@rstudio.com"),
person("Jonathan", "McPherson", role = "aut", email = "jonathan@rstudio.com"),
@@ -156,6 +156,7 @@ Collate:
'input-select.R'
'input-slider.R'
'input-submit.R'
'input-switch.R'
'input-text.R'
'input-textarea.R'
'input-utils.R'

View File

@@ -222,7 +222,6 @@ export(reactlogReset)
export(reactlogShow)
export(registerInputHandler)
export(registerThemeDependency)
export(register_devmode_option)
export(removeInputHandler)
export(removeModal)
export(removeNotification)
@@ -281,6 +280,7 @@ export(stopApp)
export(strong)
export(submitButton)
export(suppressDependencies)
export(switchInput)
export(tabPanel)
export(tabPanelBody)
export(tableOutput)
@@ -315,6 +315,7 @@ export(updateRadioButtons)
export(updateSelectInput)
export(updateSelectizeInput)
export(updateSliderInput)
export(updateSwitchInput)
export(updateTabsetPanel)
export(updateTextAreaInput)
export(updateTextInput)

View File

@@ -17,7 +17,7 @@ shiny 1.6.0.9000
* Closed #3321: New informative warning when `shiny.tag` object(s) are supplied to `...`. In this case we will continue to create an "empty" nav item and include the content on every tab, but the warning will mention the (new) `header`/`footer` args, which is likely what the user wants.
* Closed #3320: The HTML markup that `tabPanel()` et. al generate (for Bootstrap nav) is now Bootstrap 4+ compliant when used with `theme = bslib::bs_theme()`.
* Closed #1928: `NULL` values are now dropped instead of producing an empty nav item.
### Other improvements
* Shiny's core JavaScript code was converted to TypeScript. For the latest development information, please see the [README.md in `./srcts`](https://github.com/rstudio/shiny/tree/master/srcts). (#3296)
@@ -28,10 +28,6 @@ shiny 1.6.0.9000
### Bug fixes
* Closed #3374: `quoToFunction()` now works correctly with nested quosures; and as a result, quasi-quotation with rendering function (e.g., `renderPrint()`, `renderPlot()`, etc) now works as expected with nested quosures. (#3373)
* Exported `register_devmode_option()`. This method was described in the documentation for `devmode()` but was never exported. See `?devmode()` for more details on how to register Shiny Developer options using `register_devmode_option()`. (#3364)
### Library updates
* Closed #3286: Updated to Font-Awesome 5.15.2. (#3288)

View File

@@ -43,7 +43,6 @@ bootstrapPage <- function(..., title = NULL, responsive = deprecated(), theme =
}
args <- list(
jqueryDependency(),
if (!is.null(title)) tags$head(tags$title(title)),
if (is.character(theme)) {
if (length(theme) > 1) stop("`theme` must point to a single CSS file, not multiple files.")
@@ -92,10 +91,6 @@ getLang <- function(ui) {
#' @export
bootstrapLib <- function(theme = NULL) {
tagFunction(function() {
if (isRunning()) {
setCurrentTheme(theme)
}
# If we're not compiling Bootstrap Sass (from bslib), return the
# static Bootstrap build.
if (!is_bs_theme(theme)) {
@@ -117,6 +112,7 @@ bootstrapLib <- function(theme = NULL) {
# Note also that since this is shinyOptions() (and not options()), the
# option is automatically reset when the app (or session) exits
if (isRunning()) {
setCurrentTheme(theme)
registerThemeDependency(bs_theme_deps)
} else {
@@ -1014,12 +1010,9 @@ buildTabItem <- function(index, tabsetId, foundSelected, tabs = NULL,
buildNavItem <- function(divTag, tabsetId, index) {
id <- paste("tab", tabsetId, index, sep = "-")
# Get title attribute directory (not via tagGetAttribute()) so that contents
# don't get passed to as.character().
# https://github.com/rstudio/shiny/issues/3352
title <- divTag$attribs[["title"]]
value <- divTag$attribs[["data-value"]]
icon <- getIcon(iconClass = divTag$attribs[["data-icon-class"]])
title <- tagGetAttribute(divTag, "title")
value <- tagGetAttribute(divTag, "data-value")
icon <- getIcon(iconClass = tagGetAttribute(divTag, "data-icon-class"))
active <- isTabSelected(divTag)
divTag <- tagAppendAttributes(divTag, class = if (active) "active")
divTag$attribs$id <- id

View File

@@ -233,7 +233,6 @@ registered_devmode_options <- Map$new()
#' devmode_default = FALSE
#' )
#' ```
#'
#' @param name Name of option to look for in `options()`
#' @param default Default value to return if `in_devmode()` returns
#' `TRUE` and the specified option is not set in [`options()`].
@@ -244,7 +243,6 @@ registered_devmode_options <- Map$new()
#' `TRUE` and the specified option is not set in [`options()`]. For
#' `get_devmode_option()`, if `devmode_default` is missing, the
#' registered `devmode_default` value will be used.
#' @export
#' @examples
#' # Ex: Within shiny, we register the option "shiny.minified"
#' # to default to `FALSE` when in Dev Mode

65
R/input-switch.R Normal file
View File

@@ -0,0 +1,65 @@
#' Switch Input Control
#'
#' Create a switch for toggling a logical value.
#'
#' @inheritParams checkboxInput
#' @return A switch control that can be added to a UI definition.
#'
#' @family input elements
#' @seealso [checkboxInput()], [updateSwitchInput()]
#'
#' @examples
#' ## Only run examples in interactive R sessions
#' if (interactive()) {
#' ui <- fluidPage(
#' switchInput("somevalue", "Some value", FALSE),
#' verbatimTextOutput("value")
#' )
#' server <- function(input, output) {
#' output$value <- renderText({ input$somevalue })
#' }
#' shinyApp(ui, server)
#' }
#'
#' @section Server value:
#' `TRUE` if checked, `FALSE` otherwise.
#'
#' @export
switchInput <- function(inputId, label, value = FALSE, width = NULL) {
value <- restoreInput(id = inputId, default = value)
inputTag <- tags$input(
id = inputId, type = "checkbox",
checked = if (isTRUE(value)) "checked"
)
# TODO: checkboxInput() should do this too (for accessibility)?
labelTag <- shinyInputLabel(inputId, label)
tagFunction(function() {
if (getCurrentVersion() < 4) {
stop(
"switchInput() requires Bootstrap 4 or higher. ",
"Please supply `bslib::bs_theme()` to the UI's page layout function ",
"(e.g., `fluidPage(theme = bslib::bs_theme())`).",
call. = FALSE
)
}
isBS4 <- getCurrentVersion() == 4
div(
class = "shiny-input-container",
style = css(width = validateCssUnit(width)),
div(
class = if (isBS4) "custom-control custom-switch" else "form-check form-switch",
tagAppendAttributes(
inputTag, class = if (isBS4) "custom-control-input" else "form-check-input"
),
tagAppendAttributes(
labelTag, class = if (isBS4) "custom-control-label" else "form-check-label"
)
)
)
})
}

View File

@@ -2175,7 +2175,7 @@ ShinySession <- R6Class(
if (getOption("shiny.allowoutputreads", FALSE)) {
.subset2(x, 'impl')$getOutput(name)
} else {
rlang::abort(paste0("Can't read output '", name, "'"))
rlang::abort(paste0("Can't read output '", output, "'"))
}
}

View File

@@ -47,8 +47,27 @@ renderPage <- function(ui, showcase=0, testMode=FALSE) {
)
}
jquery <- function() {
version <- getOption("shiny.jquery.version", 3)
if (version == 3) {
return(htmlDependency(
"jquery", version_jquery,
c(href = "shared"),
script = "jquery.min.js"
))
}
if (version == 1) {
return(htmlDependency(
"jquery", "1.12.4",
c(href = "shared/legacy"),
script = "jquery.min.js"
))
}
stop("Unsupported version of jQuery: ", version)
}
shiny_deps <- c(
list(jqueryDependency()),
list(jquery()),
shinyDependencies()
)
@@ -63,33 +82,6 @@ renderPage <- function(ui, showcase=0, testMode=FALSE) {
enc2utf8(paste(collapse = "\n", html))
}
jqueryDependency <- function() {
version <- getOption("shiny.jquery.version", 3)
if (version == 3) {
return(htmlDependency(
"jquery", version_jquery,
src = c(
href = "shared",
file = "www/shared"
),
package = "shiny",
script = "jquery.min.js"
))
}
if (version == 1) {
return(htmlDependency(
"jquery", "1.12.4",
src = c(
href = "shared/legacy",
file = "www/shared/legacy"
),
package = "shiny",
script = "jquery.min.js"
))
}
stop("Unsupported version of jQuery: ", version)
}
shinyDependencies <- function() {
list(
bslib::bs_dependency_defer(shinyDependencyCSS),

View File

@@ -115,6 +115,12 @@ updateCheckboxInput <- function(session = getDefaultReactiveDomain(), inputId, l
session$sendInputMessage(inputId, message)
}
#' @rdname updateCheckboxInput
#' @export
updateSwitchInput <- function(session = getDefaultReactiveDomain(), inputId, label = NULL, value = NULL) {
updateCheckboxInput(session = session, inputId = inputId, label = label, value = value)
}
#' Change the label or icon of an action button on the client
#'

View File

@@ -538,10 +538,9 @@ installExprFunction <- function(expr, name, eval.env = parent.frame(2),
#' @export
quoToFunction <- function(q, label, ..stacktraceon = FALSE) {
q <- as_quosure(q)
func <- as_function(q)
# as_function returns a function that takes `...`. We want one that takes no
# args.
formals(func) <- list()
# Use new_function() instead of as_function(), because as_function() adds an
# extra parent environment. (This may not actually be a problem, though.)
func <- new_function(NULL, get_expr(q), get_env(q))
wrapFunctionLabel(func, label, ..stacktraceon = ..stacktraceon)
}

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 +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 a="",s=e||10,r="abcdefghijklmnopqrstuvwxyz0123456789",n=r.length,o=0;o<s;o++)a+=r[Math.floor(n*Math.random())];return a}},t.accessibility.liveRegion={$region:"",speak:function(e){var a=$("<div></div>");a.text(e),this.$region.html(a)},domListener:function(){var e=new MutationObserver(function(a){a.forEach(function(s){var r=$(s.target);if(r.hasClass("items"))if(r.hasClass("dropdown-active")){t.$control_input.attr("aria-expanded","true");var n=t.$dropdown_content[0].children;for(i=0;i<n.length;i++){var o=n[i].attributes;o.role||n[i].setAttribute("role","option"),o.id||n[i].setAttribute("id",t.accessibility.helpers.randomId())}}else t.$control_input.attr("aria-expanded","false"),t.$control_input.removeAttr("aria-activedescendant");else r.hasClass("active")&&r.attr("data-value")&&(t.$control_input.attr("aria-activedescendant",r.attr("id")),t.accessibility.liveRegion.speak(r.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 a=t.accessibility.helpers.randomId(),s=t.accessibility.helpers.randomId();t.$control.on("keydown",function(r){r.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(t){var e,s,a=this;void 0===a.accessibility&&(a.accessibility={}),a.accessibility.helpers={randomId:function(t){for(var e="",i=t||10,s="abcdefghijklmnopqrstuvwxyz0123456789",a=s.length,o=0;o<i;o++)e+=s[Math.floor(a*Math.random())];return e}},a.accessibility.liveRegion={$region:"",speak:function(t){var e=$("<div></div>");e.text(t),this.$region.html(e)},domListener:function(){var t=new MutationObserver(function(t){t.forEach(function(t){t=$(t.target);if(t.hasClass("items"))if(t.hasClass("dropdown-active")){a.$control_input.attr("aria-expanded","true");var e=a.$dropdown_content[0].children;for(i=0;i<e.length;i++){var s=e[i].attributes;s.role||e[i].setAttribute("role","option"),s.id||e[i].setAttribute("id",a.accessibility.helpers.randomId())}}else a.$control_input.attr("aria-expanded","false"),a.$control_input.removeAttr("aria-activedescendant");else t.hasClass("active")&&t.attr("data-value")&&(a.$control_input.attr("aria-activedescendant",t.attr("id")),a.accessibility.liveRegion.speak(t.text(),500))})});t.observe(a.$dropdown[0],{attributes:!0,attributeFilter:["class"],subtree:!0,attributeOldValue:!0}),t.observe(a.$control[0],{attributes:!0,attributeFilter:["class"]}),t.observe(a.$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=(e=a.setup,function(){e.apply(this,arguments);a.accessibility.helpers.randomId();var t=a.accessibility.helpers.randomId();a.$control.on("keydown",function(t){13===t.keyCode&&(a.settings.openOnFocus?(a.settings.openOnFocus=!1,a.focus(),setTimeout(function(){a.settings.openOnFocus=!0},0)):a.focus())}),a.$control_input.attr({role:"combobox","aria-expanded":"false",haspopup:"listbox","aria-owns":t,"aria-label":a.$wrapper.closest("[data-accessibility-selectize-label]").attr("data-accessibility-selectize-label")}),a.$dropdown_content.attr({role:"listbox",id:t}),a.accessibility.liveRegion.init()}),this.destroy=(s=a.destroy,function(){return a.accessibility.liveRegion.$region.remove(),s.apply(this,arguments)})});

View File

@@ -3127,9 +3127,9 @@
}
});
function ensureTabsetHasVisibleTab($tabset) {
var inputBinding = $tabset.data("shiny-input-binding");
if (!inputBinding.getValue($tabset)) {
if ($tabset.find("li.active").not(".dropdown").length === 0) {
var destTabValue = getFirstTab($tabset);
var inputBinding = $tabset.data("shiny-input-binding");
var evt = jQuery.Event("shiny:updateinput");
evt.binding = inputBinding;
$tabset.trigger(evt);
@@ -4730,7 +4730,7 @@
if (!restyle) {
$head.append(links);
} else {
var refreshStyle = function refreshStyle2(href2, oldSheet, onload) {
var refreshStyle = function refreshStyle2(href2, oldSheet) {
var xhr = new XMLHttpRequest();
xhr.open("GET", href2);
xhr.onload = function() {
@@ -4744,7 +4744,6 @@
setTimeout(function() {
return removeSheet(oldSheet);
}, 500);
onload();
};
xhr.send();
};
@@ -4769,29 +4768,21 @@
var oldSheet = findSheet(link.attr("href"));
var href2 = link.attr("href") + "?restyle=" + new Date().getTime();
if (isIE()) {
refreshStyle(href2, oldSheet, scheduleCssReporter);
refreshStyle(href2, oldSheet);
} else {
link.attr("href", href2);
link.attr("onload", function() {
var dummy_id = "dummy-" + Math.floor(Math.random() * 99999999);
var css_string = "#" + dummy_id + " { color: #" + Math.floor(Math.random() * 16777215).toString(16) + "; transition: 0.2s all; visibility: hidden; position: fixed; top: 0; left: 0; }";
var base64_css_string = "data:text/css;base64," + btoa(css_string);
var dummy_link = document.createElement("link");
dummy_link.rel = "stylesheet";
dummy_link.type = "text/css";
dummy_link.href = base64_css_string;
var $dummy_el = import_jquery6.default("<div id=" + dummy_id + "></div>");
import_jquery6.default(document.body).append($dummy_el);
$dummy_el.one("transitionend", function() {
sendImageSize();
removeSheet(oldSheet);
$dummy_el.remove();
});
$head.append(dummy_link);
setTimeout(function() {
return removeSheet(oldSheet);
}, 500);
});
$head.append(link);
}
});
var bindDebouncer = new Debouncer(null, Shiny.bindAll, 100);
setTimeout(function() {
return bindDebouncer.normalCall();
}, 100);
}
}
if (dep.script && !restyle) {
@@ -5172,7 +5163,7 @@
},
getState: function getState(el) {
return {
label: import_jquery6.default(el).parent().find("span").text(),
label: import_jquery6.default(el).parent().find("span, label").text(),
value: el.checked
};
},
@@ -5180,7 +5171,7 @@
if (data.hasOwnProperty("value"))
el.checked = data.value;
if (data.hasOwnProperty("label"))
import_jquery6.default(el).parent().find("span").text(data.label);
import_jquery6.default(el).parent().find("span, label").text(data.label);
import_jquery6.default(el).trigger("change");
}
});
@@ -6449,7 +6440,6 @@
}
});
inputBindings.register(fileInputBinding, "shiny.fileInputBinding");
var sendImageSize;
function initShiny() {
var shinyapp = Shiny.shinyapp = new ShinyApp();
function bindOutputs() {
@@ -6774,9 +6764,9 @@
});
}
var sendImageSizeDebouncer = new Debouncer(null, doSendImageSize, 0);
sendImageSize = function sendImageSize() {
function sendImageSize() {
sendImageSizeDebouncer.normalCall();
};
}
inputBatchSender.lastChanceCallback.push(function() {
if (sendImageSizeDebouncer.isPending())
sendImageSizeDebouncer.immediateCall();
@@ -7787,10 +7777,10 @@
return linkColor;
}
function isBS3() {
if (!import_jquery5.default.fn.tab) {
if (!import_jquery5.default.fn.tooltip) {
return false;
}
return import_jquery5.default.fn.tab.Constructor.VERSION.match(/^3\./);
return import_jquery5.default.fn.tooltip.Constructor.VERSION.match(/^3\./);
}
// src/shiny.ts

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

@@ -83,6 +83,7 @@ Other input elements:
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{switchInput}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}

View File

@@ -112,6 +112,7 @@ Other input elements:
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{switchInput}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}

View File

@@ -57,6 +57,7 @@ Other input elements:
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{switchInput}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}

View File

@@ -143,6 +143,7 @@ Other input elements:
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{switchInput}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}

View File

@@ -147,6 +147,7 @@ Other input elements:
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{switchInput}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}

View File

@@ -113,6 +113,7 @@ Other input elements:
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{switchInput}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}

View File

@@ -71,6 +71,7 @@ Other input elements:
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{switchInput}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}

View File

@@ -65,6 +65,7 @@ Other input elements:
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{switchInput}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}

View File

@@ -128,6 +128,7 @@ Other input elements:
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{switchInput}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}

View File

@@ -148,6 +148,7 @@ Other input elements:
\code{\link{radioButtons}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{switchInput}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}

View File

@@ -151,6 +151,7 @@ Other input elements:
\code{\link{radioButtons}()},
\code{\link{selectInput}()},
\code{\link{submitButton}()},
\code{\link{switchInput}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}

View File

@@ -76,6 +76,7 @@ Other input elements:
\code{\link{radioButtons}()},
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{switchInput}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}

64
man/switchInput.Rd Normal file
View File

@@ -0,0 +1,64 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/input-switch.R
\name{switchInput}
\alias{switchInput}
\title{Switch Input Control}
\usage{
switchInput(inputId, label, value = FALSE, width = NULL)
}
\arguments{
\item{inputId}{The \code{input} slot that will be used to access the value.}
\item{label}{Display label for the control, or \code{NULL} for no label.}
\item{value}{Initial value (\code{TRUE} or \code{FALSE}).}
\item{width}{The width of the input, e.g. \code{'400px'}, or \code{'100\%'};
see \code{\link[=validateCssUnit]{validateCssUnit()}}.}
}
\value{
A switch control that can be added to a UI definition.
}
\description{
Create a switch for toggling a logical value.
}
\section{Server value}{
\code{TRUE} if checked, \code{FALSE} otherwise.
}
\examples{
## Only run examples in interactive R sessions
if (interactive()) {
ui <- fluidPage(
switchInput("somevalue", "Some value", FALSE),
verbatimTextOutput("value")
)
server <- function(input, output) {
output$value <- renderText({ input$somevalue })
}
shinyApp(ui, server)
}
}
\seealso{
\code{\link[=checkboxInput]{checkboxInput()}}, \code{\link[=updateSwitchInput]{updateSwitchInput()}}
Other input elements:
\code{\link{actionButton}()},
\code{\link{checkboxGroupInput}()},
\code{\link{checkboxInput}()},
\code{\link{dateInput}()},
\code{\link{dateRangeInput}()},
\code{\link{fileInput}()},
\code{\link{numericInput}()},
\code{\link{passwordInput}()},
\code{\link{radioButtons}()},
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}
}
\concept{input elements}

View File

@@ -91,6 +91,7 @@ Other input elements:
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{switchInput}()},
\code{\link{textInput}()},
\code{\link{varSelectInput}()}
}

View File

@@ -63,6 +63,7 @@ Other input elements:
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{switchInput}()},
\code{\link{textAreaInput}()},
\code{\link{varSelectInput}()}
}

View File

@@ -2,6 +2,7 @@
% Please edit documentation in R/update-input.R
\name{updateCheckboxInput}
\alias{updateCheckboxInput}
\alias{updateSwitchInput}
\title{Change the value of a checkbox input on the client}
\usage{
updateCheckboxInput(
@@ -10,6 +11,13 @@ updateCheckboxInput(
label = NULL,
value = NULL
)
updateSwitchInput(
session = getDefaultReactiveDomain(),
inputId,
label = NULL,
value = NULL
)
}
\arguments{
\item{session}{The \code{session} object passed to function given to

View File

@@ -140,6 +140,7 @@ Other input elements:
\code{\link{selectInput}()},
\code{\link{sliderInput}()},
\code{\link{submitButton}()},
\code{\link{switchInput}()},
\code{\link{textAreaInput}()},
\code{\link{textInput}()}
}

View File

@@ -1,63 +0,0 @@
import {readdirSync, unlinkSync, writeFileSync} from "fs";
import esbuild from "esbuild";
import globalsPlugin from "esbuild-plugin-globals";
// import process from "process";
// let watch = process.argv.length >= 3 && process.argv[2] == "--watch";
let instdir = "../inst/";
let outdir = instdir + "/www/shared/";
let opts = {
bundle: false,
watch: false,
target: "es5",
sourcemap: false,
};
console.log("Building datepicker");
const locale_files = readdirSync(instdir + "www/shared/datepicker/js/locales/")
let require_files = locale_files.map(function(filename) {
return `require("./locales/${ filename }");`;
}).join("\n");
let tmpfile = instdir + "www/shared/datepicker/js/temp.js";
writeFileSync(tmpfile,
`require("./bootstrap-datepicker.js");
${require_files}`)
await esbuild.build({
...opts,
plugins:[
globalsPlugin({
jquery: "window.jQuery",
})
],
bundle: true,
entryPoints: [tmpfile],
outfile: instdir + "www/shared/datepicker/js/bootstrap-datepicker.min.js",
external: ['jquery'],
minify: true,
});
// Clean up
unlinkSync(tmpfile);
console.log("Building ionrangeslider");
await esbuild.build({
...opts,
entryPoints: [
instdir + "www/shared/ionrangeslider/js/ion.rangeSlider.js"
],
outfile: instdir + "www/shared/ionrangeslider/js/ion.rangeSlider.min.js",
minify: true,
});
console.log("Building selectize");
await esbuild.build({
...opts,
entryPoints: [
instdir + "www/shared/selectize/accessibility/js/selectize-plugin-a11y.js"
],
outfile: instdir + "www/shared/selectize/accessibility/js/selectize-plugin-a11y.min.js",
minify: true,
});

View File

@@ -42,11 +42,10 @@
},
"scripts": {
"watch": "yarn run build_shiny --watch",
"build": "yarn run build_shiny && yarn run bundle_external_libs",
"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_external_libs": "node esbuild.external_libs.mjs",
"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",

View File

@@ -1480,16 +1480,13 @@ function main(): void {
// If the given tabset has no active tabs, select the first one
function ensureTabsetHasVisibleTab($tabset) {
const inputBinding = $tabset.data("shiny-input-binding");
// Use the getValue() method to avoid duplicating the CSS selector
// for querying the DOM for the currently active tab
if (!inputBinding.getValue($tabset)) {
if ($tabset.find("li.active").not(".dropdown").length === 0) {
// Note: destTabValue may be null. We still want to proceed
// through the below logic and setValue so that the input
// value for the tabset gets updated (i.e. input$tabsetId
// should be null if there are no tabs).
const destTabValue = getFirstTab($tabset);
const inputBinding = $tabset.data("shiny-input-binding");
const evt = jQuery.Event("shiny:updateinput");
evt.binding = inputBinding;
@@ -4040,7 +4037,7 @@ function main(): void {
$head.append(links);
} else {
// This inline <style> based approach works for IE11
let refreshStyle = function (href, oldSheet, onload) {
let refreshStyle = function (href, oldSheet) {
const xhr = new XMLHttpRequest();
xhr.open("GET", href);
@@ -4053,7 +4050,6 @@ function main(): void {
$head.append(newStyle);
setTimeout(() => oldStyle.remove(), 500);
setTimeout(() => removeSheet(oldSheet), 500);
onload();
};
xhr.send();
};
@@ -4090,43 +4086,26 @@ function main(): void {
// <link> -based approach
if (isIE()) {
refreshStyle(href, oldSheet, scheduleCssReporter);
refreshStyle(href, oldSheet);
} else {
link.attr("href", href);
// Once the new <link> is loaded, schedule the old <link> to be removed
// on the next tick which is needed to avoid FOUC
link.attr("onload", () => {
const dummy_id = "dummy-" + Math.floor(Math.random() * 99999999);
const css_string =
"#" + dummy_id +
" { color: #" +
Math.floor(Math.random() * 16777215).toString(16) + "; " +
"transition: 0.2s all; " +
"visibility: hidden; " +
"position: fixed; top: 0; left: 0; }";
const base64_css_string =
"data:text/css;base64," + btoa(css_string);
let dummy_link = document.createElement("link");
dummy_link.rel = "stylesheet";
dummy_link.type = "text/css";
dummy_link.href = base64_css_string;
let $dummy_el = $("<div id=" + dummy_id + "></div>")
$(document.body).append($dummy_el);
$dummy_el
.one("transitionend", () => {
sendImageSize();
removeSheet(oldSheet);
$dummy_el.remove();
});
$head.append(dummy_link);
setTimeout(() => removeSheet(oldSheet), 500);
});
$head.append(link);
}
});
// Once the new styles are applied, CSS values that are accessible server-side
// (e.g., getCurrentOutputInfo(), output visibility, etc) may become outdated.
// At the time of writing, that means we need to do sendImageSize() &
// sendOutputHiddenState() again, which can be done by re-binding.
/* global Shiny */
const bindDebouncer = new Debouncer(null, Shiny.bindAll, 100);
setTimeout(() => bindDebouncer.normalCall(), 100);
}
}
@@ -4648,7 +4627,7 @@ function main(): void {
},
getState: function (el) {
return {
label: $(el).parent().find("span").text(),
label: $(el).parent().find("span, label").text(),
value: el.checked,
};
},
@@ -4658,7 +4637,7 @@ function main(): void {
// checkboxInput()'s label works different from other
// input labels...the label container should always exist
if (data.hasOwnProperty("label"))
$(el).parent().find("span").text(data.label);
$(el).parent().find("span, label").text(data.label);
$(el).trigger("change");
},
@@ -6407,10 +6386,6 @@ function main(): void {
});
inputBindings.register(fileInputBinding, "shiny.fileInputBinding");
// This function gets defined in initShiny() and 'hoisted' so it can be reused
// (to send CSS info) inside of Shiny.renderDependencies()
let sendImageSize;
// "init_shiny.js"
function initShiny() {
const shinyapp = (Shiny.shinyapp = new ShinyApp());
@@ -6893,9 +6868,9 @@ function main(): void {
}
const sendImageSizeDebouncer = new Debouncer(null, doSendImageSize, 0);
sendImageSize = function () {
function sendImageSize() {
sendImageSizeDebouncer.normalCall();
};
}
// Make sure sendImageSize actually gets called before the inputBatchSender
// sends data to the server.
inputBatchSender.lastChanceCallback.push(function () {

View File

@@ -364,12 +364,12 @@ function getComputedLinkColor(el: HTMLElement): string {
function isBS3(): boolean {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (!$.fn.tab) {
if (!$.fn.tooltip) {
return false;
}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return $.fn.tab.Constructor.VERSION.match(/^3\./);
return $.fn.tooltip.Constructor.VERSION.match(/^3\./);
}
export {

View File

@@ -96,19 +96,3 @@ test_that("tabPanelBody validates it's input", {
expect_error(tabPanelBody(""), "single, non-empty string")
expect_error(tabPanelBody(letters[1:2]), "single, non-empty string")
})
# https://github.com/rstudio/shiny/issues/3352
test_that("tabItem titles can contain tag objects", {
title <- tagList(tags$i("Hello"), "world")
x <- tabsetPanel(tabPanel(title, "tab content"))
x <- renderTags(x)
# Result should contain (with different whitespace):
# "<a ....> <i>Hello</i> world"
# As opposed to:
# "<a ....>&lt;i&gt;Hello&lt;/i&gt; world
expect_true(
grepl("<a [^>]+>\\s*<i>Hello</i>\\s+world", x$html)
)
})

View File

@@ -239,15 +239,3 @@ test_that("dateYMD works", {
c("2019/11/05", "")
)
})
test_that("quoToFunction handles nested quosures", {
quo_inner <- local({
x <- 1
rlang::quo(x)
})
quo_outer <- rlang::quo(!!quo_inner + 1)
func <- quoToFunction(quo_outer, "foo")
expect_identical(func(), 2)
})

View File

@@ -66,4 +66,4 @@ sass(
# Finally, run yarn build so the JS patches propogate to the minified files
withr::with_dir(rprojroot::find_package_root_file("tools"), system("yarn bundle_external_libs"))
withr::with_dir(rprojroot::find_package_root_file("tools"), system("yarn build"))