Compare commits

..

3 Commits

Author SHA1 Message Date
Joe Cheng
1d04b21876 Fix reactlog session token for "exit" actions
The "exit" actions were not being saved with the correct session
token, because on.exit() calls inside of withReactiveDomain() get
executed *after* the end of the withReactiveDomain.
2016-07-22 15:55:35 -07:00
Joe Cheng
e38c9443d9 Remove extraneous self$ prefixes 2016-07-22 15:26:07 -07:00
Joe Cheng
fb4ad55cac Fix #931: Observer memory leak
Observers were being prevented from being garbage collected by
their own onReactiveDomainEnded() event handlers. This commit
fixes that by making sure that those event handlers are only
registered when autoDestroy=TRUE, and that they are unregistered
both on destruction and when autoDestroy is changed.
2016-07-22 15:23:49 -07:00
306 changed files with 15308 additions and 28198 deletions

View File

@@ -16,5 +16,3 @@
^CONTRIBUTING.md$
^cran-comments.md$
^.*\.o$
^appveyor\.yml$
^revdep$

View File

@@ -1,8 +1,4 @@
language: r
r:
- oldrel
- release
- devel
sudo: false
cache: packages

View File

@@ -1,7 +1,8 @@
Package: shiny
Type: Package
Title: Web Application Framework for R
Version: 0.14.1.9001
Version: 0.13.2.9004
Date: 2016-02-17
Authors@R: c(
person("Winston", "Chang", role = c("aut", "cre"), email = "winston@rstudio.com"),
person("Joe", "Cheng", role = "aut", email = "joe@rstudio.com"),
@@ -14,7 +15,7 @@ Authors@R: c(
person(family = "jQuery contributors", role = c("ctb", "cph"),
comment = "jQuery library; authors listed in inst/www/shared/jquery-AUTHORS.txt"),
person(family = "jQuery UI contributors", role = c("ctb", "cph"),
comment = "jQuery UI library; authors listed in inst/www/shared/jqueryui/AUTHORS.txt"),
comment = "jQuery UI library; authors listed in inst/www/shared/jqueryui/1.10.4/AUTHORS.txt"),
person("Mark", "Otto", role = "ctb",
comment = "Bootstrap library"),
person("Jacob", "Thornton", role = "ctb",
@@ -82,11 +83,9 @@ Suggests:
ggplot2
URL: http://shiny.rstudio.com
BugReports: https://github.com/rstudio/shiny/issues
VignetteBuilder: knitr
Collate:
'app.R'
'bookmark-state-local.R'
'stack.R'
'bookmark-state.R'
'bootstrap-layout.R'
'conditions.R'
'map.R'
@@ -96,6 +95,7 @@ Collate:
'cache.R'
'diagnose.R'
'fileupload.R'
'stack.R'
'graph.R'
'hooks.R'
'html-deps.R'
@@ -116,7 +116,6 @@ Collate:
'input-slider.R'
'input-submit.R'
'input-text.R'
'input-textarea.R'
'input-utils.R'
'insert-ui.R'
'jqueryui.R'
@@ -133,10 +132,8 @@ Collate:
'render-plot.R'
'render-table.R'
'run-url.R'
'serializers.R'
'server-input-handlers.R'
'server.R'
'shiny-options.R'
'shiny.R'
'shinyui.R'
'shinywrappers.R'

View File

@@ -11,7 +11,6 @@ S3method("[",shinyoutput)
S3method("[<-",reactivevalues)
S3method("[<-",shinyoutput)
S3method("[[",reactivevalues)
S3method("[[",session_proxy)
S3method("[[",shinyoutput)
S3method("[[<-",reactivevalues)
S3method("[[<-",shinyoutput)
@@ -38,10 +37,8 @@ export(actionButton)
export(actionLink)
export(addResourcePath)
export(animationOptions)
export(applyInputHandlers)
export(as.shiny.appobj)
export(basicPage)
export(bookmarkButton)
export(bootstrapLib)
export(bootstrapPage)
export(br)
@@ -49,6 +46,7 @@ export(browserViewer)
export(brushOpts)
export(brushedPoints)
export(callModule)
export(cancelOutput)
export(captureStackTraces)
export(checkboxGroupInput)
export(checkboxInput)
@@ -68,7 +66,6 @@ export(downloadButton)
export(downloadHandler)
export(downloadLink)
export(em)
export(enableBookmarking)
export(eventReactive)
export(exprToFunction)
export(extractStackTrace)
@@ -83,9 +80,7 @@ export(flowLayout)
export(fluidPage)
export(fluidRow)
export(formatStackTrace)
export(freezeReactiveValue)
export(getDefaultReactiveDomain)
export(getShinyOption)
export(h1)
export(h2)
export(h3)
@@ -115,7 +110,6 @@ export(is.reactive)
export(is.reactivevalues)
export(is.shiny.appobj)
export(is.singleton)
export(isTruthy)
export(isolate)
export(knit_print.html)
export(knit_print.reactive)
@@ -138,14 +132,7 @@ export(ns.sep)
export(numericInput)
export(observe)
export(observeEvent)
export(onBookmark)
export(onBookmarked)
export(onFlush)
export(onFlushed)
export(onReactiveDomainEnded)
export(onRestore)
export(onRestored)
export(onSessionEnded)
export(outputOptions)
export(p)
export(pageWithSidebar)
@@ -183,7 +170,6 @@ export(renderText)
export(renderUI)
export(repeatable)
export(req)
export(restoreInput)
export(runApp)
export(runExample)
export(runGadget)
@@ -194,15 +180,12 @@ export(safeError)
export(selectInput)
export(selectizeInput)
export(serverInfo)
export(setBookmarkExclude)
export(setProgress)
export(shinyApp)
export(shinyAppDir)
export(shinyAppFile)
export(shinyOptions)
export(shinyServer)
export(shinyUI)
export(showBookmarkUrlModal)
export(showModal)
export(showNotification)
export(showReactLog)
@@ -226,7 +209,6 @@ export(tagAppendChildren)
export(tagList)
export(tagSetChildren)
export(tags)
export(textAreaInput)
export(textInput)
export(textOutput)
export(titlePanel)
@@ -239,15 +221,12 @@ export(updateDateRangeInput)
export(updateNavbarPage)
export(updateNavlistPanel)
export(updateNumericInput)
export(updateQueryString)
export(updateRadioButtons)
export(updateSelectInput)
export(updateSelectizeInput)
export(updateSliderInput)
export(updateTabsetPanel)
export(updateTextAreaInput)
export(updateTextInput)
export(urlModal)
export(validate)
export(validateCssUnit)
export(verbatimTextOutput)

1052
NEWS Normal file

File diff suppressed because it is too large Load Diff

1026
NEWS.md

File diff suppressed because it is too large Load Diff

41
R/app.R
View File

@@ -27,12 +27,6 @@
#' request to determine whether the \code{ui} should be used to handle the
#' request. Note that the entire request path must match the regular
#' expression in order for the match to be considered successful.
#' @param enableBookmarking Can be one of \code{"url"}, \code{"server"}, or
#' \code{"disable"}. This is equivalent to calling the
#' \code{\link{enableBookmarking}()} function just before calling
#' \code{shinyApp()}. With the default value (\code{NULL}), the app will
#' respect the setting from any previous calls to \code{enableBookmarking()}.
#' See \code{\link{enableBookmarking}} for more information.
#' @return An object that represents the app. Printing the object or passing it
#' to \code{\link{runApp}} will run the app.
#'
@@ -65,9 +59,10 @@
#'
#' runApp(app)
#' }
#'
#' @export
shinyApp <- function(ui=NULL, server=NULL, onStart=NULL, options=list(),
uiPattern="/", enableBookmarking = NULL) {
uiPattern="/") {
if (is.null(server)) {
stop("`server` missing from shinyApp")
}
@@ -81,24 +76,12 @@ shinyApp <- function(ui=NULL, server=NULL, onStart=NULL, options=list(),
server
}
if (!is.null(enableBookmarking)) {
bookmarkStore <- match.arg(enableBookmarking, c("url", "server", "disable"))
enableBookmarking(bookmarkStore)
}
# Store the appDir and bookmarking-related options, so that we can read them
# from within the app.
shinyOptions(appDir = getwd())
appOptions <- consumeAppOptions()
structure(
list(
httpHandler = httpHandler,
serverFuncSource = serverFuncSource,
onStart = onStart,
options = options,
appOptions = appOptions
),
options = options),
class = "shiny.appobj"
)
}
@@ -130,9 +113,7 @@ shinyAppDir <- function(appDir, options=list()) {
#' @export
shinyAppFile <- function(appFile, options=list()) {
appFile <- normalizePath(appFile, mustWork = TRUE)
appDir <- dirname(appFile)
shinyAppDir_appR(basename(appFile), appDir, options = options)
shinyAppDir_appR(basename(appFile), dirname(appFile), options = options)
}
# This reads in an app dir in the case that there's a server.R (and ui.R/www)
@@ -197,8 +178,6 @@ shinyAppDir_serverR <- function(appDir, options=list()) {
}
}
shinyOptions(appDir = appDir)
oldwd <- NULL
monitorHandle <- NULL
onStart <- function() {
@@ -220,8 +199,7 @@ shinyAppDir_serverR <- function(appDir, options=list()) {
serverFuncSource = serverFuncSource,
onStart = onStart,
onEnd = onEnd,
options = options
),
options = options),
class = "shiny.appobj"
)
}
@@ -231,13 +209,13 @@ shinyAppDir_serverR <- function(appDir, options=list()) {
# ignored when checking extensions. If any changes are detected, all connected
# Shiny sessions are reloaded.
#
# Use options(shiny.autoreload = TRUE) to enable this behavior. Since monitoring
# Use option(shiny.autoreload = TRUE) to enable this behavior. Since monitoring
# for changes is expensive (we are polling for mtimes here, nothing fancy) this
# feature is intended only for development.
#
# You can customize the file patterns Shiny will monitor by setting the
# shiny.autoreload.pattern option. For example, to monitor only ui.R:
# options(shiny.autoreload.pattern = glob2rx("ui.R"))
# option(shiny.autoreload.pattern = glob2rx("ui.R"))
#
# The return value is a function that halts monitoring when called.
initAutoReloadMonitor <- function(dir) {
@@ -274,8 +252,7 @@ initAutoReloadMonitor <- function(dir) {
# This reads in an app dir for a single-file application (e.g. app.R), and
# returns a shiny.appobj.
shinyAppDir_appR <- function(fileName, appDir, options=list())
{
shinyAppDir_appR <- function(fileName, appDir, options=list()) {
fullpath <- file.path.ci(appDir, fileName)
# This sources app.R and caches the content. When appObj() is called but
@@ -288,8 +265,6 @@ shinyAppDir_appR <- function(fileName, appDir, options=list())
if (!is.shiny.appobj(result))
stop("app.R did not return a shiny.appobj object.")
unconsumeAppOptions(result$appOptions)
return(result)
}
)

View File

@@ -1,28 +0,0 @@
# Function wrappers for saving and restoring state to/from disk when running
# Shiny locally.
#
# These functions provide a directory to the callback function.
#
# @param id A session ID to save.
# @param callback A callback function that saves state to or restores state from
# a directory. It must take one argument, \code{stateDir}, which is a
# directory to which it writes/reads.
saveInterfaceLocal <- function(id, callback) {
# Try to save in app directory
appDir <- getShinyOption("appDir", default = getwd())
stateDir <- file.path(appDir, "shiny_bookmarks", id)
if (!dirExists(stateDir))
dir.create(stateDir, recursive = TRUE)
callback(stateDir)
}
loadInterfaceLocal <- function(id, callback) {
# Try to load from app directory
appDir <- getShinyOption("appDir", default = getwd())
stateDir <- file.path(appDir, "shiny_bookmarks", id)
callback(stateDir)
}

File diff suppressed because it is too large Load Diff

View File

@@ -418,6 +418,7 @@ flowLayout <- function(..., cellArgs = list()) {
#' suitable for wrapping inputs.
#'
#' @param ... Input controls or other HTML elements.
#'
#' @export
inputPanel <- function(...) {
div(class = "shiny-input-panel",

View File

@@ -25,6 +25,7 @@ NULL
#' \code{\link{fluidPage}} function instead.
#'
#' @seealso \code{\link{fluidPage}}, \code{\link{fixedPage}}
#'
#' @export
bootstrapPage <- function(..., title = NULL, responsive = NULL, theme = NULL) {
@@ -60,7 +61,7 @@ bootstrapPage <- function(..., title = NULL, responsive = NULL, theme = NULL) {
#' @inheritParams bootstrapPage
#' @export
bootstrapLib <- function(theme = NULL) {
htmlDependency("bootstrap", "3.3.7",
htmlDependency("bootstrap", "3.3.6",
c(
href = "shared/bootstrap",
file = system.file("www/shared/bootstrap", package = "shiny")
@@ -152,6 +153,7 @@ basicPage <- function(...) {
#' div(style = "background-color: blue; width: 100%; height: 100%;")
#' )
#' )
#'
#' @export
fillPage <- function(..., padding = 0, title = NULL, bootstrap = TRUE,
theme = NULL) {
@@ -213,6 +215,7 @@ collapseSizes <- function(padding) {
#' plotOutput("distPlot")
#' )
#' )
#'
#' @export
pageWithSidebar <- function(headerPanel,
sidebarPanel,
@@ -335,9 +338,6 @@ navbarPage <- function(title,
if (inverse)
navbarClass <- paste(navbarClass, "navbar-inverse")
if (!is.null(id))
selected <- restoreInput(id = id, default = selected)
# build the tabset
tabs <- list(...)
tabset <- buildTabset(tabs, "nav navbar-nav", NULL, id, selected)
@@ -430,6 +430,7 @@ headerPanel <- function(title, windowTitle=title) {
#'
#' @param ... UI elements to include inside the panel.
#' @return The newly created panel.
#'
#' @export
wellPanel <- function(...) {
div(class="well", ...)
@@ -533,6 +534,7 @@ mainPanel <- function(..., width = 8) {
#' )
#' )
#' )
#'
#' @export
conditionalPanel <- function(condition, ...) {
div('data-display-if'=condition, ...)
@@ -633,13 +635,9 @@ tabsetPanel <- function(...,
version = "0.10.2.2")
}
if (!is.null(id))
selected <- restoreInput(id = id, default = selected)
# build the tabset
tabs <- list(...)
type <- match.arg(type)
tabset <- buildTabset(tabs, paste0("nav nav-", type), NULL, id, selected)
# create the content
@@ -702,9 +700,6 @@ navlistPanel <- function(...,
tags$li(class="navbar-brand", text)
}
if (!is.null(id))
selected <- restoreInput(id = id, default = selected)
# build the tabset
tabs <- list(...)
tabset <- buildTabset(tabs,
@@ -1500,6 +1495,7 @@ downloadLink <- function(outputId, label="Download", class=NULL) {
#' tabPanel("Summary", icon = icon("list-alt")),
#' tabPanel("Table", icon = icon("table"))
#' )
#'
#' @export
icon <- function(name, class = NULL, lib = "font-awesome") {
prefixes <- list(
@@ -1527,7 +1523,7 @@ icon <- function(name, class = NULL, lib = "font-awesome") {
# font-awesome needs an additional dependency (glyphicon is in bootstrap)
if (lib == "font-awesome") {
htmlDependencies(iconTag) <- htmlDependency(
"font-awesome", "4.6.3", c(href="shared/font-awesome"),
"font-awesome", "4.5.0", c(href="shared/font-awesome"),
stylesheet = "css/font-awesome.min.css"
)
}

View File

@@ -76,7 +76,7 @@ getCallNames <- function(calls) {
}
getLocs <- function(calls) {
vapply(calls, function(call) {
sapply(calls, function(call) {
srcref <- attr(call, "srcref", exact = TRUE)
if (!is.null(srcref)) {
srcfile <- attr(srcref, "srcfile", exact = TRUE)
@@ -86,7 +86,7 @@ getLocs <- function(calls) {
}
}
return("")
}, character(1))
})
}
#' @details \code{captureStackTraces} runs the given \code{expr} and if any

View File

@@ -94,7 +94,7 @@ FileUploadContext <- R6Class(
},
createUploadOperation = function(fileInfos) {
while (TRUE) {
id <- createUniqueId(12)
id <- paste(as.raw(p_runif(12, min=0, max=0xFF)), collapse='')
private$ids <- c(private$ids, id)
dir <- file.path(private$basedir, id)
if (!dir.create(dir))

View File

@@ -43,6 +43,7 @@ writeReactLog <- function(file=stdout(), sessionToken = NULL) {
#'
#' @param time A boolean that specifies whether or not to display the
#' time that each reactive.
#'
#' @export
showReactLog <- function(time = TRUE) {
utils::browseURL(renderReactLog(time = as.logical(time)))

View File

@@ -6,7 +6,7 @@
#' URL.
#'
#' @param dependency A single HTML dependency object, created using
#' \code{\link[htmltools]{htmlDependency}}. If the \code{src} value is named, then
#' \code{\link{htmlDependency}}. If the \code{src} value is named, then
#' \code{href} and/or \code{file} names must be present.
#'
#' @return A single HTML dependency object that has an \code{href}-named element

View File

@@ -25,6 +25,7 @@
#' R; it won't change the actual ppi of the browser.
#' @param ... Arguments to be passed through to \code{\link[grDevices]{png}}.
#' These can be used to set the width, height, background color, etc.
#'
#' @export
plotPNG <- function(func, filename=tempfile(fileext='.png'),
width=400, height=400, res=72, ...) {

View File

@@ -37,16 +37,13 @@
#' }
#'
#' @seealso \code{\link{observeEvent}} and \code{\link{eventReactive}}
#'
#' @export
actionButton <- function(inputId, label, icon = NULL, width = NULL, ...) {
value <- restoreInput(id = inputId, default = NULL)
tags$button(id=inputId,
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
type="button",
class="btn btn-default action-button",
`data-val` = value,
list(validateIcon(icon), label),
...
)
@@ -55,12 +52,9 @@ actionButton <- function(inputId, label, icon = NULL, width = NULL, ...) {
#' @rdname actionButton
#' @export
actionLink <- function(inputId, label, icon = NULL, ...) {
value <- restoreInput(id = inputId, default = NULL)
tags$a(id=inputId,
href="#",
class="action-button",
`data-val` = value,
list(validateIcon(icon), label),
...
)

View File

@@ -24,9 +24,6 @@
#' }
#' @export
checkboxInput <- function(inputId, label, value = FALSE, width = NULL) {
value <- restoreInput(id = inputId, default = value)
inputTag <- tags$input(id = inputId, type="checkbox")
if (!is.null(value) && value)
inputTag$attribs$checked <- "checked"

View File

@@ -38,8 +38,6 @@
checkboxGroupInput <- function(inputId, label, choices, selected = NULL,
inline = FALSE, width = NULL) {
selected <- restoreInput(id = inputId, default = selected)
# resolve names
choices <- choicesWithNames(choices)
if (!is.null(selected))

View File

@@ -21,26 +21,23 @@
#'
#' @inheritParams textInput
#' @param value The starting date. Either a Date object, or a string in
#' \code{yyyy-mm-dd} format. If NULL (the default), will use the current date
#' in the client's time zone.
#' \code{yyyy-mm-dd} format. If NULL (the default), will use the current
#' date in the client's time zone.
#' @param min The minimum allowed date. Either a Date object, or a string in
#' \code{yyyy-mm-dd} format.
#' @param max The maximum allowed date. Either a Date object, or a string in
#' \code{yyyy-mm-dd} format.
#' @param format The format of the date to display in the browser. Defaults to
#' \code{"yyyy-mm-dd"}.
#' @param startview The date range shown when the input object is first clicked.
#' Can be "month" (the default), "year", or "decade".
#' @param startview The date range shown when the input object is first
#' clicked. Can be "month" (the default), "year", or "decade".
#' @param weekstart Which day is the start of the week. Should be an integer
#' from 0 (Sunday) to 6 (Saturday).
#' @param language The language used for month and day names. Default is "en".
#' Other valid values include "ar", "az", "bg", "bs", "ca", "cs", "cy", "da",
#' "de", "el", "en-AU", "en-GB", "eo", "es", "et", "eu", "fa", "fi", "fo",
#' "fr-CH", "fr", "gl", "he", "hr", "hu", "hy", "id", "is", "it-CH", "it",
#' "ja", "ka", "kh", "kk", "ko", "kr", "lt", "lv", "me", "mk", "mn", "ms",
#' "nb", "nl-BE", "nl", "no", "pl", "pt-BR", "pt", "ro", "rs-latin", "rs",
#' "ru", "sk", "sl", "sq", "sr-latin", "sr", "sv", "sw", "th", "tr", "uk",
#' "vi", "zh-CN", and "zh-TW".
#' Other valid values include "bg", "ca", "cs", "da", "de", "el", "es", "fi",
#' "fr", "he", "hr", "hu", "id", "is", "it", "ja", "kr", "lt", "lv", "ms",
#' "nb", "nl", "pl", "pt", "pt-BR", "ro", "rs", "rs-latin", "ru", "sk", "sl",
#' "sv", "sw", "th", "tr", "uk", "zh-CN", and "zh-TW".
#'
#' @family input elements
#' @seealso \code{\link{dateRangeInput}}, \code{\link{updateDateInput}}
@@ -63,7 +60,7 @@
#'
#' # Use different language and different first day of week
#' dateInput("date5", "Date:",
#' language = "ru",
#' language = "de",
#' weekstart = 1),
#'
#' # Start with decade view instead of default month view
@@ -84,36 +81,29 @@ dateInput <- function(inputId, label, value = NULL, min = NULL, max = NULL,
if (inherits(min, "Date")) min <- format(min, "%Y-%m-%d")
if (inherits(max, "Date")) max <- format(max, "%Y-%m-%d")
value <- restoreInput(id = inputId, default = value)
attachDependencies(
tags$div(id = inputId,
class = "shiny-date-input form-group shiny-input-container",
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
tags$div(id = inputId,
class = "shiny-date-input form-group shiny-input-container",
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
controlLabel(inputId, label),
tags$input(type = "text",
class = "form-control",
`data-date-language` = language,
`data-date-week-start` = weekstart,
`data-date-format` = format,
`data-date-start-view` = startview,
`data-min-date` = min,
`data-max-date` = max,
`data-initial-date` = value
controlLabel(inputId, label),
tags$input(type = "text",
# datepicker class necessary for dropdown to display correctly
class = "form-control datepicker",
`data-date-language` = language,
`data-date-weekstart` = weekstart,
`data-date-format` = format,
`data-date-start-view` = startview,
`data-min-date` = min,
`data-max-date` = max,
`data-initial-date` = value
)
),
datePickerDependency
)
}
datePickerDependency <- htmlDependency(
"bootstrap-datepicker", "1.6.4", c(href = "shared/datepicker"),
"bootstrap-datepicker", "1.0.2", c(href = "shared/datepicker"),
script = "js/bootstrap-datepicker.min.js",
stylesheet = "css/bootstrap-datepicker3.min.css",
# Need to enable noConflict mode. See #1346.
head = "<script>
(function() {
var datepicker = $.fn.datepicker.noConflict();
$.fn.bsDatepicker = datepicker;
})();
</script>"
)
stylesheet = "css/datepicker.css")

View File

@@ -82,10 +82,6 @@ dateRangeInput <- function(inputId, label, start = NULL, end = NULL,
if (inherits(min, "Date")) min <- format(min, "%Y-%m-%d")
if (inherits(max, "Date")) max <- format(max, "%Y-%m-%d")
restored <- restoreInput(id = inputId, default = list(start, end))
start <- restored[[1]]
end <- restored[[2]]
attachDependencies(
div(id = inputId,
class = "shiny-date-range-input form-group shiny-input-container",

View File

@@ -72,48 +72,16 @@
fileInput <- function(inputId, label, multiple = FALSE, accept = NULL,
width = NULL) {
restoredValue <- restoreInput(id = inputId, default = NULL)
# Catch potential edge case - ensure that it's either NULL or a data frame.
if (!is.null(restoredValue) && !is.data.frame(restoredValue)) {
warning("Restored value for ", inputId, " has incorrect format.")
restoredValue <- NULL
}
if (!is.null(restoredValue)) {
restoredValue <- toJSON(restoredValue, strict_atomic = FALSE)
}
inputTag <- tags$input(
id = inputId,
name = inputId,
type = "file",
style = "display: none;",
`data-restore` = restoredValue
)
inputTag <- tags$input(id = inputId, name = inputId, type = "file")
if (multiple)
inputTag$attribs$multiple <- "multiple"
if (length(accept) > 0)
inputTag$attribs$accept <- paste(accept, collapse=',')
div(class = "form-group shiny-input-container",
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
label %AND% tags$label(label),
div(class = "input-group",
tags$label(class = "input-group-btn",
span(class = "btn btn-default btn-file",
"Browse...",
inputTag
)
),
tags$input(type = "text", class = "form-control",
placeholder = "No file selected", readonly = "readonly"
)
),
inputTag,
tags$div(
id=paste(inputId, "_progress", sep=""),
class="progress progress-striped active shiny-file-input-progress",

View File

@@ -1,3 +1,4 @@
#' Create a numeric input control
#'
#' Create an input control for entry of numeric values
@@ -28,8 +29,6 @@
numericInput <- function(inputId, label, value, min = NA, max = NA, step = NA,
width = NULL) {
value <- restoreInput(id = inputId, default = value)
# build input tag
inputTag <- tags$input(id = inputId, type = "number", class="form-control",
value = formatNoSci(value))

View File

@@ -55,8 +55,6 @@ radioButtons <- function(inputId, label, choices, selected = NULL,
# resolve names
choices <- choicesWithNames(choices)
selected <- restoreInput(id = inputId, default = selected)
# default value if it's not specified
selected <- if (is.null(selected)) choices[[1]] else {
validateSelected(selected, choices, inputId)

View File

@@ -54,9 +54,6 @@
selectInput <- function(inputId, label, choices, selected = NULL,
multiple = FALSE, selectize = TRUE, width = NULL,
size = NULL) {
selected <- restoreInput(id = inputId, default = selected)
# resolve names
choices <- choicesWithNames(choices)
@@ -172,7 +169,7 @@ selectizeIt <- function(inputId, select, options, nonempty = FALSE) {
if ('drag_drop' %in% options$plugins) {
selectizeDep <- list(selectizeDep, htmlDependency(
'jqueryui', '1.12.1', c(href = 'shared/jqueryui'),
'jqueryui', '1.11.4', c(href = 'shared/jqueryui'),
script = 'jquery-ui.min.js'
))
}

View File

@@ -85,8 +85,6 @@ sliderInput <- function(inputId, label, min, max, value, step = NULL,
version = "0.10.2.2")
}
value <- restoreInput(id = inputId, default = value)
# If step is NULL, use heuristic to set the step size.
findStepSize <- function(min, max, step) {
if (!is.null(step)) return(step)
@@ -163,6 +161,7 @@ sliderInput <- function(inputId, label, min, max, value, step = NULL,
`data-grid` = ticks,
`data-grid-num` = n_ticks,
`data-grid-snap` = FALSE,
`data-prettify-separator` = sep,
`data-prefix` = pre,
`data-postfix` = post,
`data-keyboard` = TRUE,
@@ -174,12 +173,6 @@ sliderInput <- function(inputId, label, min, max, value, step = NULL,
`data-timezone` = timezone
))
if (sep == "") {
sliderProps$`data-prettify-enabled` <- "0"
} else {
sliderProps$`data-prettify-separator` <- sep
}
# Replace any TRUE and FALSE with "true" and "false"
sliderProps <- lapply(sliderProps, function(x) {
if (identical(x, TRUE)) "true"
@@ -249,6 +242,7 @@ hasDecimals <- function(value) {
#' or list of tags (using \code{\link{tag}} and friends), or raw HTML (using
#' \code{\link{HTML}}).
#' @param pauseButton Similar to \code{playButton}, but for the pause button.
#'
#' @export
animationOptions <- function(interval=1000,
loop=FALSE,

View File

@@ -32,8 +32,6 @@
textInput <- function(inputId, label, value = "", width = NULL,
placeholder = NULL) {
value <- restoreInput(id = inputId, default = value)
div(class = "form-group shiny-input-container",
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
label %AND% tags$label(label, `for` = inputId),

View File

@@ -1,69 +0,0 @@
#' Create a textarea input control
#'
#' Create a textarea input control for entry of unstructured text values.
#'
#' @inheritParams textInput
#' @param height The height of the input, e.g. \code{'400px'}, or
#' \code{'100\%'}; see \code{\link{validateCssUnit}}.
#' @param cols Value of the visible character columns of the input, e.g.
#' \code{80}. If used with \code{width}, \code{width} will take precedence in
#' the browser's rendering.
#' @param rows The value of the visible character rows of the input, e.g.
#' \code{6}. If used with \code{height}, \code{height} will take precedence in
#' the browser's rendering.
#' @param 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.
#' @return A textarea input control that can be added to a UI definition.
#'
#' @family input elements
#' @seealso \code{\link{updateTextAreaInput}}
#'
#' @examples
#' ## Only run examples in interactive R sessions
#' if (interactive()) {
#'
#' ui <- fluidPage(
#' textAreaInput("caption", "Caption", "Data Summary", width = "1000px"),
#' verbatimTextOutput("value")
#' )
#' server <- function(input, output) {
#' output$value <- renderText({ input$caption })
#' }
#' shinyApp(ui, server)
#'
#' }
#' @export
textAreaInput <- function(inputId, label, value = "", width = NULL, height = NULL,
cols = NULL, rows = NULL, placeholder = NULL, resize = NULL) {
value <- restoreInput(id = inputId, default = value)
if (!is.null(resize)) {
resize <- match.arg(resize, c("both", "none", "vertical", "horizontal"))
}
style <- paste(
if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
if (!is.null(height)) paste0("height: ", validateCssUnit(height), ";"),
if (!is.null(resize)) paste0("resize: ", resize, ";")
)
# Workaround for tag attribute=character(0) bug:
# https://github.com/rstudio/htmltools/issues/65
if (length(style) == 0) style <- NULL
div(class = "form-group shiny-input-container",
label %AND% tags$label(label, `for` = inputId),
tags$textarea(
id = inputId,
class = "form-control",
placeholder = placeholder,
style = style,
rows = rows,
cols = cols,
value
)
)
}

View File

@@ -4,13 +4,10 @@ controlLabel <- function(controlName, label) {
# Before shiny 0.9, `selected` refers to names/labels of `choices`; now it
# refers to values. Below is a function for backward compatibility. It also
# coerces the value to `character`.
# refers to values. Below is a function for backward compatibility.
validateSelected <- function(selected, choices, inputId) {
# this line accomplishes two tings:
# - coerces selected to character
# - drops name, otherwise toJSON() keeps it too
selected <- as.character(selected)
# drop names, otherwise toJSON() keeps them too
selected <- unname(selected)
# if you are using optgroups, you're using shiny > 0.10.0, and you should
# already know that `selected` must be a value instead of a label
if (needOptgroup(choices)) return(selected)
@@ -51,10 +48,10 @@ generateOptions <- function(inputId, choices, selected, inline, type = 'checkbox
# If inline, there's no wrapper div, and the label needs a class like
# checkbox-inline.
if (inline) {
tags$label(class = paste0(type, "-inline"), inputTag, tags$span(HTML(name)))
tags$label(class = paste0(type, "-inline"), inputTag, tags$span(name))
} else {
tags$div(class = type,
tags$label(inputTag, tags$span(HTML(name)))
tags$label(inputTag, tags$span(name))
)
}
},
@@ -66,7 +63,7 @@ generateOptions <- function(inputId, choices, selected, inline, type = 'checkbox
# Takes a vector or list, and adds names (same as the value) to any entries
# without names. Coerces all leaf nodes to `character`.
# without names.
choicesWithNames <- function(choices) {
# Take a vector or list, and convert to list. Also, if any children are
# vectors with length > 1, convert those to list. If the list is unnamed,
@@ -82,7 +79,7 @@ choicesWithNames <- function(choices) {
if (is.list(val))
listify(val)
else if (length(val) == 1 && is.null(names(val)))
as.character(val)
val
else
makeNamed(as.list(val))
})

View File

@@ -73,6 +73,7 @@
#' # Complete app with UI and server components
#' shinyApp(ui, server)
#' }
#'
#' @export
insertUI <- function(selector,
where = c("beforeBegin", "afterBegin", "beforeEnd", "afterEnd"),
@@ -154,6 +155,7 @@ insertUI <- function(selector,
#' # Complete app with UI and server components
#' shinyApp(ui, server)
#' }
#'
#' @export
removeUI <- function(selector,
multiple = FALSE,

View File

@@ -53,6 +53,7 @@
#' over text). The default is \code{"auto"}, which is equivalent to
#' \code{ifelse(draggable, "move", "inherit")}.
#' @return An HTML element or list of elements.
#'
#' @export
absolutePanel <- function(...,
top = NULL, left = NULL, right = NULL, bottom = NULL,
@@ -79,6 +80,8 @@ absolutePanel <- function(...,
if (isTRUE(draggable)) {
divTag <- tagAppendAttributes(divTag, class='draggable')
return(tagList(
# IMPORTANT NOTE: If you update jqueryui, make sure you DON'T include the datepicker,
# as it collides with our bootstrap datepicker!
singleton(tags$head(tags$script(src='shared/jqueryui/jquery-ui.min.js'))),
divTag,
tags$script('$(".draggable").draggable();')

View File

@@ -36,15 +36,11 @@ removeModal <- function(session = getDefaultReactiveDomain()) {
#' @param ... UI elements for the body of the modal dialog box.
#' @param title An optional title for the dialog.
#' @param footer UI for footer. Use \code{NULL} for no footer.
#' @param size One of \code{"s"} for small, \code{"m"} (the default) for medium,
#' or \code{"l"} for large.
#' @param easyClose If \code{TRUE}, the modal dialog can be dismissed by
#' clicking outside the dialog box, or be pressing the Escape key. If
#' \code{FALSE} (the default), the modal dialog can't be dismissed in those
#' ways; instead it must be dismissed by clicking on the dismiss button, or
#' from a call to \code{\link{removeModal}} on the server.
#' @param fade If \code{FALSE}, the modal dialog will have no fade-in animation
#' (it will simply appear rather than fade in to view).
#'
#' @examples
#' if (interactive()) {
@@ -84,7 +80,7 @@ removeModal <- function(session = getDefaultReactiveDomain()) {
#' )
#'
#'
#' # Display a modal that requires valid input before continuing.
# Display a modal that requires valid input before continuing.
#' shinyApp(
#' ui = basicPage(
#' actionButton("show", "Show modal dialog"),
@@ -124,8 +120,7 @@ removeModal <- function(session = getDefaultReactiveDomain()) {
#' # message.
#' observeEvent(input$ok, {
#' # Check that data object exists and is data frame.
#' if (!is.null(input$dataset) && nzchar(input$dataset) &&
#' exists(input$dataset) && is.data.frame(get(input$dataset))) {
#' if (exists(input$dataset) && is.data.frame(get(input$dataset))) {
#' vals$data <- get(input$dataset)
#' removeModal()
#' } else {
@@ -145,18 +140,13 @@ removeModal <- function(session = getDefaultReactiveDomain()) {
#' }
#' @export
modalDialog <- function(..., title = NULL, footer = modalButton("Dismiss"),
size = c("m", "s", "l"), easyClose = FALSE, fade = TRUE) {
easyClose = FALSE) {
size <- match.arg(size)
cls <- if (fade) "modal fade" else "modal"
div(id = "shiny-modal", class = cls, tabindex = "-1",
div(id = "shiny-modal", class = "modal fade", tabindex = "-1",
`data-backdrop` = if (!easyClose) "static",
`data-keyboard` = if (!easyClose) "false",
div(
class = "modal-dialog",
class = switch(size, s = "modal-sm", m = NULL, l = "modal-lg"),
div(class = "modal-dialog",
div(class = "modal-content",
if (!is.null(title)) div(class = "modal-header",
tags$h4(class = "modal-title", title)

View File

@@ -1,4 +1,4 @@
# Creates an object whose $ and [[ pass through to the parent
# Creates an object whose $ and $<- pass through to the parent
# session, unless the name is matched in ..., in which case
# that value is returned instead. (See Decorator pattern.)
createSessionProxy <- function(parentSession, ...) {
@@ -14,24 +14,18 @@ createSessionProxy <- function(parentSession, ...) {
#' @export
`$.session_proxy` <- function(x, name) {
if (name %in% names(.subset2(x, "overrides")))
.subset2(x, "overrides")[[name]]
if (name %in% names(x[["overrides"]]))
x[["overrides"]][[name]]
else
.subset2(x, "parent")[[name]]
x[["parent"]][[name]]
}
#' @export
`[[.session_proxy` <- `$.session_proxy`
#' @export
`$<-.session_proxy` <- function(x, name, value) {
stop("Attempted to assign value on session proxy.")
x[["parent"]][[name]] <- value
x
}
`[[<-.session_proxy` <- `$<-.session_proxy`
#' Invoke a Shiny module
#'
#' Shiny's module feature lets you break complicated UI and server logic into
@@ -48,6 +42,7 @@ createSessionProxy <- function(parentSession, ...) {
#'
#' @return The return value, if any, from executing the module server function
#' @seealso \url{http://shiny.rstudio.com/articles/modules.html}
#'
#' @export
callModule <- function(module, id, ..., session = getDefaultReactiveDomain()) {
childScope <- session$makeScope(id)

View File

@@ -75,7 +75,7 @@ showNotification <- function(ui, action = NULL, duration = 5,
{
if (is.null(id))
id <- createUniqueId(8)
id <- randomID()
res <- processDeps(ui, session)
actionRes <- processDeps(action, session)

View File

@@ -12,14 +12,6 @@
#' method is called. Calling \code{close} will cause the progress panel
#' to be removed.
#'
#' As of version 0.14, the progress indicators use Shiny's new notification API.
#' If you want to use the old styling (for example, you may have used customized
#' CSS), you can use \code{style="old"} each time you call
#' \code{Progress$new()}. If you don't want to set the style each time
#' \code{Progress$new} is called, you can instead call
#' \code{\link{shinyOptions}(progress.style="old")} just once, inside the server
#' function.
#'
#' \strong{Methods}
#' \describe{
#' \item{\code{initialize(session, min = 0, max = 1)}}{
@@ -56,10 +48,6 @@
#' @param value A numeric value at which to set
#' the progress bar, relative to \code{min} and \code{max}.
#' \code{NULL} hides the progress bar, if it is currently visible.
#' @param style Progress display style. If \code{"notification"} (the default),
#' the progress indicator will show using Shiny's notification API. If
#' \code{"old"}, use the same HTML and CSS used in Shiny 0.13.2 and below
#' (this is for backward-compatibility).
#' @param amount Single-element numeric vector; the value at which to set
#' the progress bar, relative to \code{min} and \code{max}.
#' \code{NULL} hides the progress bar, if it is currently visible.
@@ -101,22 +89,18 @@ Progress <- R6Class(
portable = TRUE,
public = list(
initialize = function(session = getDefaultReactiveDomain(),
min = 0, max = 1,
style = getShinyOption("progress.style", default = "notification"))
{
initialize = function(session = getDefaultReactiveDomain(), min = 0, max = 1) {
if (is.null(session$progressStack))
stop("'session' is not a ShinySession object.")
private$session <- session
private$id <- createUniqueId(8)
private$id <- randomID()
private$min <- min
private$max <- max
private$style <- match.arg(style, choices = c("notification", "old"))
private$value <- NULL
private$closed <- FALSE
session$sendProgress('open', list(id = private$id, style = private$style))
session$sendProgress('open', list(id = private$id))
},
set = function(value = NULL, message = NULL, detail = NULL) {
@@ -138,8 +122,7 @@ Progress <- R6Class(
id = private$id,
message = message,
detail = detail,
value = value,
style = private$style
value = value
))
private$session$sendProgress('update', data)
@@ -165,9 +148,7 @@ Progress <- R6Class(
return()
}
private$session$sendProgress('close',
list(id = private$id, style = private$style)
)
private$session$sendProgress('close', list(id = private$id))
private$closed <- TRUE
}
),
@@ -177,7 +158,6 @@ Progress <- R6Class(
id = character(0),
min = numeric(0),
max = numeric(0),
style = character(0),
value = NULL,
closed = logical(0)
)
@@ -206,14 +186,6 @@ Progress <- R6Class(
#' is not common) or otherwise cannot be encapsulated by a single scope. In that
#' case, you can use the \code{Progress} reference class.
#'
#' As of version 0.14, the progress indicators use Shiny's new notification API.
#' If you want to use the old styling (for example, you may have used customized
#' CSS), you can use \code{style="old"} each time you call
#' \code{withProgress()}. If you don't want to set the style each time
#' \code{withProgress} is called, you can instead call
#' \code{\link{shinyOptions}(progress.style="old")} just once, inside the server
#' function.
#'
#' @param session The Shiny session object, as provided by \code{shinyServer} to
#' the server function. The default is to automatically find the session by
#' using the current reactive domain.
@@ -234,10 +206,6 @@ Progress <- R6Class(
#' displayed to the user, or \code{NULL} to hide the current detail message
#' (if any). The detail message will be shown with a de-emphasized appearance
#' relative to \code{message}.
#' @param style Progress display style. If \code{"notification"} (the default),
#' the progress indicator will show using Shiny's notification API. If
#' \code{"old"}, use the same HTML and CSS used in Shiny 0.13.2 and below
#' (this is for backward-compatibility).
#' @param value Single-element numeric vector; the value at which to set the
#' progress bar, relative to \code{min} and \code{max}. \code{NULL} hides the
#' progress bar, if it is currently visible.
@@ -269,12 +237,10 @@ Progress <- R6Class(
#' @rdname withProgress
#' @export
withProgress <- function(expr, min = 0, max = 1,
value = min + (max - min) * 0.1,
message = NULL, detail = NULL,
style = getShinyOption("progress.style", default = "notification"),
session = getDefaultReactiveDomain(),
env = parent.frame(), quoted = FALSE)
{
value = min + (max - min) * 0.1,
message = NULL, detail = NULL,
session = getDefaultReactiveDomain(),
env = parent.frame(), quoted = FALSE) {
if (!quoted)
expr <- substitute(expr)
@@ -282,9 +248,7 @@ withProgress <- function(expr, min = 0, max = 1,
if (is.null(session$progressStack))
stop("'session' is not a ShinySession object.")
style <- match.arg(style, c("notification", "old"))
p <- Progress$new(session, min = min, max = max, style = style)
p <- Progress$new(session, min = min, max = max)
session$progressStack$push(p)
on.exit({

View File

@@ -21,8 +21,10 @@ Context <- R6Class(
withReactiveDomain(.domain, {
env <- .getReactiveEnvironment()
.graphEnterContext(id)
on.exit(.graphExitContext(id), add = TRUE)
env$runWith(self, func)
tryCatch(
env$runWith(self, func),
finally = .graphExitContext(id)
)
})
},
invalidate = function() {
@@ -115,16 +117,13 @@ ReactiveEnvironment <- R6Class(
addPendingFlush = function(ctx, priority) {
.pendingFlush$enqueue(ctx, priority)
},
hasPendingFlush = function() {
return(!.pendingFlush$isEmpty())
},
flush = function() {
# If already in a flush, don't start another one
if (.inFlush) return()
.inFlush <<- TRUE
on.exit(.inFlush <<- FALSE)
while (hasPendingFlush()) {
while (!.pendingFlush$isEmpty()) {
ctx <- .pendingFlush$dequeue()
ctx$executeFlushCallbacks()
}

View File

@@ -41,10 +41,11 @@ NULL
# `reactlog(logEntry)`.
#
## ------------------------------------------------------------------------
createMockDomain <- function() {
createMockDomain <- function(token = createUniqueId(4)) {
callbacks <- Callbacks$new()
ended <- FALSE
domain <- new.env(parent = emptyenv())
domain$token <- token
domain$onEnded <- function(callback) {
return(callbacks$register(callback))
}

View File

@@ -47,7 +47,6 @@ ReactiveValues <- R6Class(
# For debug purposes
.label = character(0),
.values = 'environment',
.metadata = 'environment',
.dependents = 'environment',
# Dependents for the list of all names, including hidden
.namesDeps = 'Dependents',
@@ -61,40 +60,32 @@ ReactiveValues <- R6Class(
p_randomInt(1000, 10000),
sep="")
.values <<- new.env(parent=emptyenv())
.metadata <<- new.env(parent=emptyenv())
.dependents <<- new.env(parent=emptyenv())
.namesDeps <<- Dependents$new()
.allValuesDeps <<- Dependents$new()
.valuesDeps <<- Dependents$new()
},
get = function(key) {
# Register the "downstream" reactive which is accessing this value, so
# that we know to invalidate them when this value changes.
ctx <- .getReactiveEnvironment()$currentContext()
dep.key <- paste(key, ':', ctx$id, sep='')
if (!exists(dep.key, envir=.dependents, inherits=FALSE)) {
if (!exists(dep.key, where=.dependents, inherits=FALSE)) {
.graphDependsOn(ctx$id, sprintf('%s$%s', .label, key))
.dependents[[dep.key]] <- ctx
assign(dep.key, ctx, pos=.dependents, inherits=FALSE)
ctx$onInvalidate(function() {
rm(list=dep.key, envir=.dependents, inherits=FALSE)
rm(list=dep.key, pos=.dependents, inherits=FALSE)
})
}
if (isFrozen(key))
reactiveStop()
if (!exists(key, envir=.values, inherits=FALSE))
if (!exists(key, where=.values, inherits=FALSE))
NULL
else
.values[[key]]
base::get(key, pos=.values, inherits=FALSE)
},
set = function(key, value) {
hidden <- substr(key, 1, 1) == "."
if (exists(key, envir=.values, inherits=FALSE)) {
if (identical(.values[[key]], value)) {
if (exists(key, where=.values, inherits=FALSE)) {
if (identical(base::get(key, pos=.values, inherits=FALSE), value)) {
return(invisible())
}
}
@@ -107,14 +98,14 @@ ReactiveValues <- R6Class(
else
.valuesDeps$invalidate()
.values[[key]] <- value
assign(key, value, pos=.values, inherits=FALSE)
.graphValueChange(sprintf('names(%s)', .label), ls(.values, all.names=TRUE))
.graphValueChange(sprintf('%s (all)', .label), as.list(.values))
.graphValueChange(sprintf('%s$%s', .label, key), value)
dep.keys <- objects(
envir=.dependents,
pos=.dependents,
pattern=paste('^\\Q', key, ':', '\\E', '\\d+$', sep=''),
all.names=TRUE
)
@@ -127,54 +118,18 @@ ReactiveValues <- R6Class(
)
invisible()
},
mset = function(lst) {
lapply(base::names(lst),
function(name) {
self$set(name, lst[[name]])
})
},
names = function() {
.graphDependsOn(.getReactiveEnvironment()$currentContext()$id,
sprintf('names(%s)', .label))
.namesDeps$register()
return(ls(.values, all.names=TRUE))
},
# Get a metadata value. Does not trigger reactivity.
getMeta = function(key, metaKey) {
# Make sure to use named (not numeric) indexing into list.
metaKey <- as.character(metaKey)
.metadata[[key]][[metaKey]]
},
# Set a metadata value. Does not trigger reactivity.
setMeta = function(key, metaKey, value) {
# Make sure to use named (not numeric) indexing into list.
metaKey <- as.character(metaKey)
if (!exists(key, envir = .metadata, inherits = FALSE)) {
.metadata[[key]] <<- list()
}
.metadata[[key]][[metaKey]] <<- value
},
# Mark a value as frozen If accessed while frozen, a shiny.silent.error will
# be thrown.
freeze = function(key) {
setMeta(key, "frozen", TRUE)
},
thaw = function(key) {
setMeta(key, "frozen", NULL)
},
isFrozen = function(key) {
isTRUE(getMeta(key, "frozen"))
},
toList = function(all.names=FALSE) {
.graphDependsOn(.getReactiveEnvironment()$currentContext()$id,
sprintf('%s (all)', .label))
@@ -185,7 +140,6 @@ ReactiveValues <- R6Class(
return(as.list(.values, all.names=all.names))
},
.setLabel = function(label) {
.label <<- label
}
@@ -232,6 +186,7 @@ ReactiveValues <- R6Class(
#' these objects must be named.
#'
#' @seealso \code{\link{isolate}} and \code{\link{is.reactivevalues}}.
#'
#' @export
reactiveValues <- function(...) {
args <- list(...)
@@ -362,25 +317,10 @@ as.list.reactivevalues <- function(x, all.names=FALSE, ...) {
#' # isolate() can also be used when calling from outside a reactive context (e.g.
#' # at the console)
#' isolate(reactiveValuesToList(values))
#'
#' @export
reactiveValuesToList <- function(x, all.names=FALSE) {
# Default case
res <- .subset2(x, 'impl')$toList(all.names)
prefix <- .subset2(x, 'ns')("")
# Special handling for namespaces
if (nzchar(prefix)) {
fullNames <- names(res)
# Filter out items that match namespace
fullNames <- fullNames[substring(fullNames, 1, nchar(prefix)) == prefix]
res <- res[fullNames]
# Remove namespace prefix
names(res) <- substring(fullNames, nchar(prefix) + 1)
}
res
.subset2(x, 'impl')$toList(all.names)
}
# This function is needed because str() on a reactivevalues object will call
@@ -394,67 +334,6 @@ str.reactivevalues <- function(object, indent.str = " ", ...) {
utils::str(class(object))
}
#' Freeze a reactive value
#'
#' This freezes a reactive value. If the value is accessed while frozen, a
#' "silent" exception is raised and the operation is stopped. This is the same
#' thing that happens if \code{req(FALSE)} is called. The value is thawed
#' (un-frozen; accessing it will no longer raise an exception) when the current
#' reactive domain is flushed. In a Shiny application, this occurs after all of
#' the observers are executed.
#'
#' @param x A \code{\link{reactiveValues}} object (like \code{input}).
#' @param name The name of a value in the \code{\link{reactiveValues}} object.
#'
#' @seealso \code{\link{req}}
#' @examples
#' ## Only run this examples in interactive R sessions
#' if (interactive()) {
#'
#' ui <- fluidPage(
#' selectInput("data", "Data Set", c("mtcars", "pressure")),
#' checkboxGroupInput("cols", "Columns (select 2)", character(0)),
#' plotOutput("plot")
#' )
#'
#' server <- function(input, output, session) {
#' observe({
#' data <- get(input$data)
#' # Sets a flag on input$cols to essentially do req(FALSE) if input$cols
#' # is accessed. Without this, an error will momentarily show whenever a
#' # new data set is selected.
#' freezeReactiveValue(input, "cols")
#' updateCheckboxGroupInput(session, "cols", choices = names(data))
#' })
#'
#' output$plot <- renderPlot({
#' # When a new data set is selected, input$cols will have been invalidated
#' # above, and this will essentially do the same as req(FALSE), causing
#' # this observer to stop and raise a silent exception.
#' cols <- input$cols
#' data <- get(input$data)
#'
#' if (length(cols) == 2) {
#' plot(data[[ cols[1] ]], data[[ cols[2] ]])
#' }
#' })
#' }
#'
#' shinyApp(ui, server)
#' }
#' @export
freezeReactiveValue <- function(x, name) {
domain <- getDefaultReactiveDomain()
if (is.null(getDefaultReactiveDomain)) {
stop("freezeReactiveValue() must be called when a default reactive domain is active.")
}
domain$freezeValue(x, name)
invisible()
}
# Observable ----------------------------------------------------------------
Observable <- R6Class(
@@ -620,6 +499,7 @@ Observable <- R6Class(
#' isolate(reactiveB())
#' isolate(reactiveC())
#' isolate(reactiveD())
#'
#' @export
reactive <- function(x, env = parent.frame(), quoted = FALSE, label = NULL,
domain = getDefaultReactiveDomain(),
@@ -682,7 +562,7 @@ srcrefToLabel <- function(srcref, defaultLabel) {
#' @export
print.reactive <- function(x, ...) {
label <- attr(x, "observable", exact = TRUE)$.label
label <- attr(x, "observable")$.label
cat(label, "\n")
}
@@ -693,7 +573,7 @@ is.reactive <- function(x) inherits(x, "reactive")
# Return the number of times that a reactive expression or observer has been run
execCount <- function(x) {
if (is.reactive(x))
return(attr(x, "observable", exact = TRUE)$.execCount)
return(attr(x, "observable")$.execCount)
else if (inherits(x, 'Observer'))
return(x$.execCount)
else
@@ -711,10 +591,6 @@ Observer <- R6Class(
.domain = 'ANY',
.priority = numeric(0),
.autoDestroy = logical(0),
# A function that, when invoked, unsubscribes the autoDestroy
# listener (or NULL if autodestroy is disabled for this observer).
# We must unsubscribe when this observer is destroyed, or else
# the observer cannot be garbage collected until the session ends.
.autoDestroyHandle = 'ANY',
.invalidateCallbacks = list(),
.execCount = integer(0),
@@ -737,10 +613,10 @@ registerDebugHook("observerFunc", environment(), label)
..stacktraceon..(observerFunc())
else
observerFunc(),
# It's OK for shiny.silent.error errors to cause an observer to stop running
shiny.silent.error = function(e) NULL
# validation = function(e) NULL,
# shiny.output.cancel = function(e) NULL
validation = function(e) {
# It's OK for a validation error to cause an observer to stop
# running
}
)
}
.label <<- label
@@ -922,8 +798,8 @@ registerDebugHook("observerFunc", environment(), label)
#' soon as their dependencies change, they schedule themselves to re-execute.
#'
#' Starting with Shiny 0.10.0, observers are automatically destroyed by default
#' when the \link[=domains]{domain} that owns them ends (e.g. when a Shiny
#' session ends).
#' when the \link[=domains]{domain} that owns them ends (e.g. when a Shiny session
#' ends).
#'
#' @param x An expression (quoted or unquoted). Any return value will be
#' ignored.
@@ -934,13 +810,12 @@ registerDebugHook("observerFunc", environment(), label)
#' This is useful when you want to use an expression that is stored in a
#' variable; to do so, it must be quoted with \code{quote()}.
#' @param label A label for the observer, useful for debugging.
#' @param suspended If \code{TRUE}, start the observer in a suspended state. If
#' \code{FALSE} (the default), start in a non-suspended state.
#' @param suspended If \code{TRUE}, start the observer in a suspended state.
#' If \code{FALSE} (the default), start in a non-suspended state.
#' @param priority An integer or numeric that controls the priority with which
#' this observer should be executed. A higher value means higher priority: an
#' observer with a higher priority value will execute before all observers
#' with lower priority values. Positive, negative, and zero values are
#' allowed.
#' this observer should be executed. An observer with a given priority level
#' will always execute sooner than all observers with a lower priority level.
#' Positive, negative, and zero values are allowed.
#' @param domain See \link{domains}.
#' @param autoDestroy If \code{TRUE} (the default), the observer will be
#' automatically destroyed when its domain (if any) ends.
@@ -999,6 +874,7 @@ registerDebugHook("observerFunc", environment(), label)
#' # In a normal Shiny app, the web client will trigger flush events. If you
#' # are at the console, you can force a flush with flushReact()
#' shiny:::flushReact()
#'
#' @export
observe <- function(x, env=parent.frame(), quoted=FALSE, label=NULL,
suspended=FALSE, priority=0,
@@ -1038,9 +914,9 @@ observe <- function(x, env=parent.frame(), quoted=FALSE, label=NULL,
#' }
#' @export
makeReactiveBinding <- function(symbol, env = parent.frame()) {
if (exists(symbol, envir = env, inherits = FALSE)) {
initialValue <- env[[symbol]]
rm(list = symbol, envir = env, inherits = FALSE)
if (exists(symbol, where = env, inherits = FALSE)) {
initialValue <- get(symbol, pos = env, inherits = FALSE)
rm(list = symbol, pos = env, inherits = FALSE)
}
else
initialValue <- NULL
@@ -1148,6 +1024,7 @@ setAutoflush <- local({
#'
#' shinyApp(ui, server)
#' }
#'
#' @export
reactiveTimer <- function(intervalMs=1000, session = getDefaultReactiveDomain()) {
dependents <- Map$new()
@@ -1306,6 +1183,7 @@ coerceToFunc <- function(x) {
#' data()
#' })
#' }
#'
#' @export
reactivePoll <- function(intervalMillis, session, checkFunc, valueFunc) {
intervalMillis <- coerceToFunc(intervalMillis)
@@ -1383,6 +1261,7 @@ reactivePoll <- function(intervalMillis, session, checkFunc, valueFunc) {
#' })
#' }
#' }
#'
#' @export
reactiveFileReader <- function(intervalMillis, session, filePath, readFunc, ...) {
filePath <- coerceToFunc(filePath)
@@ -1470,6 +1349,7 @@ reactiveFileReader <- function(intervalMillis, session, filePath, readFunc, ...)
#'
#' # isolate also works if the reactive expression accesses values from the
#' # input object, like input$x
#'
#' @export
isolate <- function(expr) {
ctx <- Context$new(getDefaultReactiveDomain(), '[isolate]', type='isolate')
@@ -1491,6 +1371,7 @@ isolate <- function(expr) {
#' @return The value of \code{expr}.
#'
#' @seealso \code{\link{isolate}}
#'
#' @export
maskReactiveContext <- function(expr) {
.getReactiveEnvironment()$runWith(NULL, function() {
@@ -1617,6 +1498,7 @@ maskReactiveContext <- function(expr) {
#' }
#' shinyApp(ui=ui, server=server)
#' }
#'
#' @export
observeEvent <- function(eventExpr, handlerExpr,
event.env = parent.frame(), event.quoted = FALSE,

View File

@@ -165,9 +165,9 @@ renderPlot <- function(expr, width='auto', height='auto', res=72, ...,
plotObj <- reactive(label = "plotObj", {
if (execOnResize) {
dims <- getDims()
} else {
isolate({ dims <- getDims() })
} else {
dims <- getDims()
}
if (is.null(dims$width) || is.null(dims$height) ||
@@ -185,9 +185,6 @@ renderPlot <- function(expr, width='auto', height='auto', res=72, ...,
success <-FALSE
tryCatch(
{
# This is necessary to enable displaylist recording
grDevices::dev.control(displaylist = "enable")
# Actually perform the plotting
result <- withVisible(func())
success <- TRUE
@@ -418,39 +415,23 @@ getPrevPlotCoordmap <- function(width, height) {
# Given a ggplot_build_gtable object, return a coordmap for it.
getGgplotCoordmap <- function(p, pixelratio, res) {
# Structure of ggplot objects changed after 2.1.0
new_ggplot <- (utils::packageVersion("ggplot2") > "2.1.0")
if (!inherits(p, "ggplot_build_gtable"))
return(NULL)
# Given a built ggplot object, return x and y domains (data space coords) for
# each panel.
find_panel_info <- function(b) {
if (new_ggplot) {
layout <- b$layout$panel_layout
} else {
layout <- b$panel$layout
}
layout <- b$panel$layout
# Convert factor to numbers
layout$PANEL <- as.integer(as.character(layout$PANEL))
# Names of facets
facet <- b$plot$facet
facet_vars <- NULL
if (new_ggplot) {
facet <- b$layout$facet
if (inherits(facet, "FacetGrid")) {
facet_vars <- vapply(c(facet$params$cols, facet$params$rows), as.character, character(1))
} else if (inherits(facet, "FacetWrap")) {
facet_vars <- vapply(facet$params$facets, as.character, character(1))
}
} else {
facet <- b$plot$facet
if (inherits(facet, "grid")) {
facet_vars <- vapply(c(facet$cols, facet$rows), as.character, character(1))
} else if (inherits(facet, "wrap")) {
facet_vars <- vapply(facet$facets, as.character, character(1))
}
if (inherits(facet, "grid")) {
facet_vars <- vapply(c(facet$cols, facet$rows), as.character, character(1))
} else if (inherits(facet, "wrap")) {
facet_vars <- vapply(facet$facets, as.character, character(1))
}
# Iterate over each row in the layout data frame
@@ -492,11 +473,7 @@ getGgplotCoordmap <- function(p, pixelratio, res) {
# Given a single range object (representing the data domain) from a built
# ggplot object, return the domain.
find_panel_domain <- function(b, panel_num, scalex_num = 1, scaley_num = 1) {
if (new_ggplot) {
range <- b$layout$panel_ranges[[panel_num]]
} else {
range <- b$panel$ranges[[panel_num]]
}
range <- b$panel$ranges[[panel_num]]
domain <- list(
left = range$x.range[1],
right = range$x.range[2],
@@ -505,13 +482,9 @@ getGgplotCoordmap <- function(p, pixelratio, res) {
)
# Check for reversed scales
if (new_ggplot) {
xscale <- b$layout$panel_scales$x[[scalex_num]]
yscale <- b$layout$panel_scales$y[[scaley_num]]
} else {
xscale <- b$panel$x_scales[[scalex_num]]
yscale <- b$panel$y_scales[[scaley_num]]
}
xscale <- b$panel$x_scales[[scalex_num]]
yscale <- b$panel$y_scales[[scaley_num]]
if (!is.null(xscale$trans) && xscale$trans$name == "reverse") {
domain$left <- -domain$left
domain$right <- -domain$right
@@ -546,18 +519,10 @@ getGgplotCoordmap <- function(p, pixelratio, res) {
y_names <- character(0)
# Continuous scales have a trans; discrete ones don't
if (new_ggplot) {
if (!is.null(b$layout$panel_scales$x[[scalex_num]]$trans))
x_names <- b$layout$panel_scales$x[[scalex_num]]$trans$name
if (!is.null(b$layout$panel_scales$y[[scaley_num]]$trans))
y_names <- b$layout$panel_scales$y[[scaley_num]]$trans$name
} else {
if (!is.null(b$panel$x_scales[[scalex_num]]$trans))
x_names <- b$panel$x_scales[[scalex_num]]$trans$name
if (!is.null(b$panel$y_scales[[scaley_num]]$trans))
y_names <- b$panel$y_scales[[scaley_num]]$trans$name
}
if (!is.null(b$panel$x_scales[[scalex_num]]$trans))
x_names <- b$panel$x_scales[[scalex_num]]$trans$name
if (!is.null(b$panel$y_scales[[scaley_num]]$trans))
y_names <- b$panel$y_scales[[scaley_num]]$trans$name
coords <- b$plot$coordinates
if (!is.null(coords$trans)) {
@@ -611,11 +576,6 @@ getGgplotCoordmap <- function(p, pixelratio, res) {
)
}
# Look for CoordFlip
if (inherits(b$plot$coordinates, "CoordFlip")) {
mappings[c("x", "y")] <- mappings[c("y", "x")]
}
mappings_cache <<- mappings
mappings
}

View File

@@ -46,6 +46,7 @@
#' @param outputArgs A list of arguments to be passed through to the
#' implicit call to \code{\link{tableOutput}} when \code{renderTable} is
#' used in an interactive R Markdown document.
#'
#' @export
renderTable <- function(expr, striped = FALSE, hover = FALSE,
bordered = FALSE, spacing = c("s", "xs", "m", "l"),
@@ -79,8 +80,6 @@ renderTable <- function(expr, striped = FALSE, hover = FALSE,
digitsWrapper <- createWrapper(digits)
naWrapper <- createWrapper(na)
dots <- list(...) ## used later (but defined here because of scoping)
renderFunc <- function(shinysession, name, ...) {
striped <- stripedWrapper()
hover <- hoverWrapper()
@@ -114,6 +113,7 @@ renderTable <- function(expr, striped = FALSE, hover = FALSE,
return(NULL)
# Separate the ... args to pass to xtable() vs print.xtable()
dots <- list(...)
xtable_argnames <- setdiff(names(formals(xtable)), c("x", "..."))
xtable_args <- dots[intersect(names(dots), xtable_argnames)]
non_xtable_args <- dots[setdiff(names(dots), xtable_argnames)]
@@ -156,30 +156,15 @@ renderTable <- function(expr, striped = FALSE, hover = FALSE,
# Set up print args
print_args <- list(
x = xtable_res,
xtable_res,
type = 'html',
include.rownames = {
if ("include.rownames" %in% names(dots)) dots$include.rownames
else rownames
},
include.colnames = {
if ("include.colnames" %in% names(dots)) dots$include.colnames
else colnames
},
NA.string = {
if ("NA.string" %in% names(dots)) dots$NA.string
else na
},
html.table.attributes =
paste0({
if ("html.table.attributes" %in% names(dots)) dots$html.table.attributes
else ""
}, " ",
"class = '", htmlEscape(classNames, TRUE), "' ",
"style = 'width:", validateCssUnit(width), ";'"))
include.rownames = rownames,
include.colnames = colnames,
NA.string = na,
html.table.attributes = paste0("class = '", htmlEscape(classNames, TRUE), "' ",
"style = 'width:", validateCssUnit(width), ";'"))
print_args <- c(print_args, non_xtable_args)
print_args <- print_args[unique(names(print_args))]
# Capture the raw html table returned by print.xtable(), and store it in
# a variable for further processing

View File

@@ -1,72 +0,0 @@
# For most types of values, simply return the value unchanged.
serializerDefault <- function(value, stateDir) {
value
}
serializerFileInput <- function(value, stateDir = NULL) {
# File inputs can be serialized only if there's a stateDir
if (is.null(stateDir)) {
return(serializerUnserializable())
}
# value is a data frame. When persisting files, we need to copy the file to
# the persistent dir and then strip the original path before saving.
newpaths <- file.path(stateDir, basename(value$datapath))
file.copy(value$datapath, newpaths, overwrite = TRUE)
value$datapath <- basename(newpaths)
value
}
# Return a sentinel value that represents "unserializable". This is applied to
# for example, passwords and actionButtons.
serializerUnserializable <- function(value, stateDir) {
structure(
list(),
serializable = FALSE
)
}
# Is this an "unserializable" sentinel value?
isUnserializable <- function(x) {
identical(
attr(x, "serializable", exact = TRUE),
FALSE
)
}
# Given a reactiveValues object and optional directory for saving state, apply
# serializer function to each of the values, and return a list of the returned
# values. This function passes stateDir to the serializer functions, so if
# stateDir is non-NULL, it can have a side effect of writing values to disk (in
# stateDir).
serializeReactiveValues <- function(values, exclude, stateDir = NULL) {
impl <- .subset2(values, "impl")
# Get named list where keys and values are the names of inputs; we'll retrieve
# actual values later.
vals <- isolate(impl$names())
vals <- setdiff(vals, exclude)
names(vals) <- vals
# Get values and apply serializer functions
vals <- lapply(vals, function(name) {
val <- impl$get(name)
# Get the serializer function for this input value. If none specified, use
# the default.
serializer <- impl$getMeta(name, "shiny.serializer")
if (is.null(serializer))
serializer <- serializerDefault
# Apply serializer function.
serializer(val, stateDir)
})
# Filter out any values that were marked as unserializable.
vals <- Filter(Negate(isUnserializable), vals)
vals
}

View File

@@ -71,72 +71,6 @@ removeInputHandler <- function(type){
inputHandlers$remove(type)
}
# Apply input handler to a single input value
applyInputHandler <- function(name, val) {
splitName <- strsplit(name, ':')[[1]]
if (length(splitName) > 1) {
if (!inputHandlers$containsKey(splitName[[2]])) {
# No input handler registered for this type
stop("No handler registered for type ", name)
}
inputName <- splitName[[1]]
# Get the function for processing this type of input
inputHandler <- inputHandlers$get(splitName[[2]])
return(inputHandler(val, shinysession, inputName))
} else if (is.list(val) && is.null(names(val))) {
return(unlist(val, recursive = TRUE))
} else {
return(val)
}
}
#' Apply input handlers to raw input values
#'
#' The purpose of this function is to make it possible for external packages to
#' test Shiny inputs. It takes a named list of raw input values, applies input
#' handlers to those values, and then returns a named list of the processed
#' values.
#'
#' The raw input values should be in a named list. Some values may have names
#' like \code{"x:shiny.date"}. This function would apply the \code{"shiny.date"}
#' input handler to the value, and then rename the result to \code{"x"}, in the
#' output.
#'
#' @param inputs A named list of input values.
#'
#' @seealso registerInputHandler
#'
#' @examples
#' applyInputHandlers(list(
#' "m1" = list(list(1, 2), list(3, 4)),
#' "m2:shiny.matrix" = list(list(1, 2), list(3, 4)),
#'
#' "d1" = "2016-01-01",
#' "d2:shiny.date" = "2016-01-01", # Date object
#'
#' "n1" = NULL,
#' "n2:shiny.number" = NULL # Converts to NA
#' ))
#' @export
applyInputHandlers <- function(inputs) {
inputs <- mapply(applyInputHandler, names(inputs), inputs, SIMPLIFY = FALSE)
# Convert names like "button1:shiny.action" to "button1"
names(inputs) <- vapply(
names(inputs),
function(name) { strsplit(name, ":")[[1]][1] },
FUN.VALUE = character(1)
)
inputs
}
# Takes a list-of-lists and returns a matrix. The lists
# must all be the same length. NULL is replaced by NA.
registerInputHandler("shiny.matrix", function(data, ...) {
@@ -155,29 +89,10 @@ registerInputHandler("shiny.number", function(val, ...){
ifelse(is.null(val), NA, val)
})
registerInputHandler("shiny.password", function(val, shinysession, name) {
# Mark passwords as not serializable
.subset2(shinysession$input, "impl")$setMeta(name, "shiny.serializer", serializerUnserializable)
val
})
registerInputHandler("shiny.date", function(val, ...){
# First replace NULLs with NA, then convert to Date vector
datelist <- ifelse(lapply(val, is.null), NA, val)
res <- NULL
tryCatch({
res <- as.Date(unlist(datelist))
},
error = function(e) {
# It's possible for client to send a string like "99999-01-01", which
# as.Date can't handle.
warning(e$message)
res <<- as.Date(rep(NA, length(datelist)))
}
)
res
as.Date(unlist(datelist))
})
registerInputHandler("shiny.datetime", function(val, ...){
@@ -189,41 +104,8 @@ registerInputHandler("shiny.datetime", function(val, ...){
as.POSIXct(unlist(times), origin = "1970-01-01", tz = "UTC")
})
registerInputHandler("shiny.action", function(val, shinysession, name) {
registerInputHandler("shiny.action", function(val, ...) {
# mark up the action button value with a special class so we can recognize it later
class(val) <- c(class(val), "shinyActionButtonValue")
val
})
registerInputHandler("shiny.file", function(val, shinysession, name) {
# This function is only used when restoring a Shiny fileInput. When a file is
# uploaded the usual way, it takes a different code path and won't hit this
# function.
if (is.null(val))
return(NULL)
# The data will be a named list of lists; convert to a data frame.
val <- as.data.frame(lapply(val, unlist), stringsAsFactors = FALSE)
# `val$datapath` should be a filename without a path, for security reasons.
if (basename(val$datapath) != val$datapath) {
stop("Invalid '/' found in file input path.")
}
# Prepend the persistent dir
oldfile <- file.path(getCurrentRestoreContext()$dir, val$datapath)
# Copy the original file to a new temp dir, so that a restored session can't
# modify the original.
newdir <- file.path(tempdir(), createUniqueId(12))
dir.create(newdir)
val$datapath <- file.path(newdir, val$datapath)
file.copy(oldfile, val$datapath)
# Need to mark this input value with the correct serializer. When a file is
# uploaded the usual way (instead of being restored), this occurs in
# session$`@uploadEnd`.
.subset2(shinysession$input, "impl")$setMeta(name, "shiny.serializer", serializerFileInput)
val
})

View File

@@ -49,6 +49,7 @@ registerClient <- function(client) {
#'
#' @examples
#' addResourcePath('datasets', system.file('data', package='datasets'))
#'
#' @export
addResourcePath <- function(prefix, directoryPath) {
prefix <- prefix[1]
@@ -140,6 +141,7 @@ resourcePathHandler <- function(req) {
#' })
#' }
#' }
#'
#' @export
shinyServer <- function(func) {
.globals$server <- list(func)
@@ -230,105 +232,121 @@ createAppHandlers <- function(httpHandlers, serverFuncSource) {
msg <- decodeMessage(msg)
# Set up a restore context from .clientdata_url_search before
# handling all the input values, because the restore context may be
# used by an input handler (like the one for "shiny.file"). This
# should only happen once, when the app starts.
if (is.null(shinysession$restoreContext)) {
bookmarkStore <- getShinyOption("bookmarkStore", default = "disable")
if (bookmarkStore == "disable") {
# If bookmarking is disabled, use empty context
shinysession$restoreContext <- RestoreContext$new()
} else {
# If there's bookmarked state, save it on the session object
shinysession$restoreContext <- RestoreContext$new(msg$data$.clientdata_url_search)
# Do our own list simplifying here. sapply/simplify2array give names to
# character vectors, which is rarely what we want.
if (!is.null(msg$data)) {
for (name in names(msg$data)) {
val <- msg$data[[name]]
splitName <- strsplit(name, ':')[[1]]
if (length(splitName) > 1) {
msg$data[[name]] <- NULL
if (!inputHandlers$containsKey(splitName[[2]])){
# No input handler registered for this type
stop("No handler registered for type ", name)
}
msg$data[[ splitName[[1]] ]] <-
inputHandlers$get(splitName[[2]])(
val,
shinysession,
splitName[[1]] )
}
else if (is.list(val) && is.null(names(val))) {
val_flat <- unlist(val, recursive = TRUE)
if (is.null(val_flat)) {
# This is to assign NULL instead of deleting the item
msg$data[name] <- list(NULL)
} else {
msg$data[[name]] <- val_flat
}
}
}
}
withRestoreContext(shinysession$restoreContext, {
switch(
msg$method,
init = {
msg$data <- applyInputHandlers(msg$data)
switch(
msg$method,
init = {
serverFunc <- withReactiveDomain(NULL, serverFuncSource())
if (!identicalFunctionBodies(serverFunc, appvars$server)) {
appvars$server <- serverFunc
if (!is.null(appvars$server))
{
# Tag this function as the Shiny server function. A debugger may use this
# tag to give this function special treatment.
# It's very important that it's appvars$server itself and NOT a copy that
# is invoked, otherwise new breakpoints won't be picked up.
attr(appvars$server, "shinyServerFunction") <- TRUE
registerDebugHook("server", appvars, "Server Function")
}
serverFunc <- withReactiveDomain(NULL, serverFuncSource())
if (!identicalFunctionBodies(serverFunc, appvars$server)) {
appvars$server <- serverFunc
if (!is.null(appvars$server))
{
# Tag this function as the Shiny server function. A debugger may use this
# tag to give this function special treatment.
# It's very important that it's appvars$server itself and NOT a copy that
# is invoked, otherwise new breakpoints won't be picked up.
attr(appvars$server, "shinyServerFunction") <- TRUE
registerDebugHook("server", appvars, "Server Function")
}
}
# Check for switching into/out of showcase mode
if (.globals$showcaseOverride &&
exists(".clientdata_url_search", where = msg$data)) {
mode <- showcaseModeOfQuerystring(msg$data$.clientdata_url_search)
if (!is.null(mode))
shinysession$setShowcase(mode)
}
# Check for switching into/out of showcase mode
if (.globals$showcaseOverride &&
exists(".clientdata_url_search", where = msg$data)) {
mode <- showcaseModeOfQuerystring(msg$data$.clientdata_url_search)
if (!is.null(mode))
shinysession$setShowcase(mode)
}
shinysession$manageInputs(msg$data)
shinysession$manageInputs(msg$data)
# The client tells us what singletons were rendered into
# the initial page
if (!is.null(msg$data$.clientdata_singletons)) {
shinysession$singletons <- strsplit(
msg$data$.clientdata_singletons, ',')[[1]]
}
# The client tells us what singletons were rendered into
# the initial page
if (!is.null(msg$data$.clientdata_singletons)) {
shinysession$singletons <- strsplit(
msg$data$.clientdata_singletons, ',')[[1]]
}
local({
args <- argsForServerFunc(serverFunc, shinysession)
local({
args <- argsForServerFunc(serverFunc, shinysession)
withReactiveDomain(shinysession, {
do.call(
# No corresponding ..stacktraceoff; the server func is pure
# user code
wrapFunctionLabel(appvars$server, "server",
..stacktraceon = TRUE
),
args
)
})
withReactiveDomain(shinysession, {
do.call(
# No corresponding ..stacktraceoff; the server func is pure
# user code
wrapFunctionLabel(appvars$server, "server",
..stacktraceon = TRUE
),
args
)
})
},
update = {
shinysession$manageInputs(msg$data)
},
shinysession$dispatch(msg)
)
shinysession$manageHiddenOutputs()
})
},
update = {
shinysession$manageInputs(msg$data)
},
shinysession$dispatch(msg)
)
shinysession$manageHiddenOutputs()
if (exists(".shiny__stdout", globalenv()) &&
exists("HTTP_GUID", ws$request)) {
# safe to assume we're in shiny-server
shiny_stdout <- get(".shiny__stdout", globalenv())
if (exists(".shiny__stdout", globalenv()) &&
exists("HTTP_GUID", ws$request)) {
# safe to assume we're in shiny-server
shiny_stdout <- get(".shiny__stdout", globalenv())
# eNter a flushReact
writeLines(paste("_n_flushReact ", get("HTTP_GUID", ws$request),
" @ ", sprintf("%.3f", as.numeric(Sys.time())),
sep=""), con=shiny_stdout)
flush(shiny_stdout)
# eNter a flushReact
writeLines(paste("_n_flushReact ", get("HTTP_GUID", ws$request),
" @ ", sprintf("%.3f", as.numeric(Sys.time())),
sep=""), con=shiny_stdout)
flush(shiny_stdout)
flushReact()
flushReact()
# eXit a flushReact
writeLines(paste("_x_flushReact ", get("HTTP_GUID", ws$request),
" @ ", sprintf("%.3f", as.numeric(Sys.time())),
sep=""), con=shiny_stdout)
flush(shiny_stdout)
} else {
flushReact()
}
flushAllSessions()
# eXit a flushReact
writeLines(paste("_x_flushReact ", get("HTTP_GUID", ws$request),
" @ ", sprintf("%.3f", as.numeric(Sys.time())),
sep=""), con=shiny_stdout)
flush(shiny_stdout)
} else {
flushReact()
}
lapply(appsByToken$values(), function(shinysession) {
shinysession$flushOutput()
NULL
})
})
}
@@ -429,12 +447,6 @@ startApp <- function(appObj, port, host, quiet) {
message('\n', 'Listening on domain socket ', port)
}
mask <- attr(port, 'mask')
if (is.null(mask)) {
stop("`port` is not a valid domain socket (missing `mask` attribute). ",
"Note that if you're using the default `host` + `port` ",
"configuration (and not domain sockets), then `port` must ",
"be numeric, not a string.")
}
return(startPipeServer(port, mask, handlerManager$createHttpuvApp()))
}
}
@@ -448,7 +460,10 @@ serviceApp <- function() {
}
flushReact()
flushAllSessions()
for (shinysession in appsByToken$values()) {
shinysession$flushOutput()
}
}
# If this R session is interactive, then call service() with a short timeout
@@ -550,11 +565,6 @@ runApp <- function(appDir=getwd(),
handlerManager$clear()
}, add = TRUE)
# Enable per-app Shiny options
oldOptionSet <- .globals$options
on.exit({
.globals$options <- oldOptionSet
},add = TRUE)
if (is.null(host) || is.na(host))
host <- '0.0.0.0'
@@ -566,7 +576,7 @@ runApp <- function(appDir=getwd(),
workerId(workerId)
if (inShinyServer()) {
if (nzchar(Sys.getenv('SHINY_PORT'))) {
# If SHINY_PORT is set, we're running under Shiny Server. Check the version
# to make sure it is compatible. Older versions of Shiny Server don't set
# SHINY_SERVER_VERSION, those will return "" which is considered less than
@@ -671,12 +681,6 @@ runApp <- function(appDir=getwd(),
}
appParts <- as.shiny.appobj(appDir)
# Extract appOptions (which is a list) and store them as shinyOptions, for
# this app. (This is the only place we have to store settings that are
# accessible both the UI and server portion of the app.)
unconsumeAppOptions(appParts$appOptions)
# Set up the onEnd before we call onStart, so that it gets called even if an
# error happens in onStart.
if (!is.null(appParts$onEnd))
@@ -739,6 +743,7 @@ runApp <- function(appDir=getwd(),
#'
#' @param returnValue The value that should be returned from
#' \code{\link{runApp}}.
#'
#' @export
stopApp <- function(returnValue = invisible()) {
# reterror will indicate whether retval is an error (i.e. it should be passed
@@ -857,6 +862,7 @@ runExample <- function(example=NA,
#' # ...or as a single app object
#' runGadget(shinyApp(ui, server))
#' }
#'
#' @export
runGadget <- function(app, server = NULL, port = getOption("shiny.port"),
viewer = paneViewer(), stopOnCancel = TRUE) {
@@ -952,9 +958,3 @@ browserViewer <- function(browser = getOption("browser")) {
utils::browseURL(url, browser = browser)
}
}
# Returns TRUE if we're running in Shiny Server or other hosting environment,
# otherwise returns FALSE.
inShinyServer <- function() {
nzchar(Sys.getenv('SHINY_PORT'))
}

View File

@@ -1,83 +0,0 @@
.globals$options <- list()
#' @param name Name of an option to get.
#' @param default Value to be returned if the option is not currently set.
#' @rdname shinyOptions
#' @export
getShinyOption <- function(name, default = NULL) {
# Make sure to use named (not numeric) indexing
name <- as.character(name)
if (name %in% names(.globals$options))
.globals$options[[name]]
else
default
}
#' Get or set Shiny options
#'
#' \code{getShinyOption} retrieves the value of a Shiny option.
#' \code{shinyOptions} sets the value of Shiny options; it can also be used to
#' return a list of all currently-set Shiny options.
#'
#' There is a global option set, which is available by default. When a Shiny
#' application is run with \code{\link{runApp}}, that option set is duplicated
#' and the new option set is available for getting or setting values. If options
#' are set from global.R, app.R, ui.R, or server.R, or if they are set from
#' inside the server function, then the options will be scoped to the
#' application. When the application exits, the new option set is discarded and
#' the global option set is restored.
#'
#' @param ... Options to set, with the form \code{name = value}.
#'
#' @examples
#' \dontrun{
#' shinyOptions(myOption = 10)
#' getShinyOption("myOption")
#' }
#' @export
shinyOptions <- function(...) {
newOpts <- list(...)
if (length(newOpts) > 0) {
.globals$options <- dropNulls(mergeVectors(.globals$options, newOpts))
invisible(.globals$options)
} else {
.globals$options
}
}
# Eval an expression with a new option set
withLocalOptions <- function(expr) {
oldOptionSet <- .globals$options
on.exit(.globals$options <- oldOptionSet)
expr
}
# Get specific shiny options and put them in a list, reset those shiny options,
# and then return the options list. This should be during the creation of a
# shiny app object, which happens before another option frame is added to the
# options stack (the new option frame is added when the app is run). This
# function "consumes" the options when the shinyApp object is created, so the
# options won't affect another app that is created later.
consumeAppOptions <- function() {
options <- list(
appDir = getwd(),
bookmarkStore = getShinyOption("bookmarkStore")
)
shinyOptions(appDir = NULL, bookmarkStore = NULL)
options
}
# Do the inverse of consumeAppOptions. This should be called once the app is
# started.
unconsumeAppOptions <- function(options) {
if (!is.null(options)) {
do.call(shinyOptions, options)
}
}

509
R/shiny.R
View File

@@ -53,10 +53,10 @@ NULL
#'
#' 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"))}
#' \code{option(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
#' by setting e.g. \code{option(shiny.autoreload.interval = 2000)} (every
#' two seconds).}
#' \item{shiny.reactlog}{If \code{TRUE}, enable logging of reactive events,
#' which can be viewed later with the \code{\link{showReactLog}} function.
@@ -123,14 +123,10 @@ createUniqueId <- function(bytes, prefix = "", suffix = "") {
toJSON <- function(x, ..., dataframe = "columns", null = "null", na = "null",
auto_unbox = TRUE, digits = getOption("shiny.json.digits", 16),
use_signif = TRUE, force = TRUE, POSIXt = "ISO8601", UTC = TRUE,
rownames = FALSE, keep_vec_names = TRUE, strict_atomic = TRUE) {
if (strict_atomic) {
x <- I(x)
}
rownames = FALSE, keep_vec_names = TRUE) {
# I(x) is so that length-1 atomic vectors get put in [].
jsonlite::toJSON(x, dataframe = dataframe, null = null, na = na,
jsonlite::toJSON(I(x), dataframe = dataframe, null = null, na = na,
auto_unbox = auto_unbox, digits = digits, use_signif = use_signif,
force = force, POSIXt = POSIXt, UTC = UTC, rownames = rownames,
keep_vec_names = keep_vec_names, json_verbatim = TRUE, ...)
@@ -286,12 +282,6 @@ workerId <- local({
#' \code{addCustomMessageHandler} will be invoked each time
#' \code{sendCustomMessage} is called on the server.
#' }
#' \item{sendBinaryMessage(type, message)}{
#' Similar to \code{sendCustomMessage}, but the message must be a raw vector
#' and the registration method on the client is
#' \code{Shiny.addBinaryMessageHandler(type, function(message){...})}. The
#' message argument on the client will be a \href{https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView}{DataView}.
#' }
#' \item{sendInputMessage(inputId, message)}{
#' Sends a message to an input on the session's client web page; if the input
#' is present and bound on the page at the time the message is received, then
@@ -300,29 +290,6 @@ workerId <- local({
#' from Shiny apps, but through friendlier wrapper functions like
#' \code{\link{updateTextInput}}.
#' }
#' \item{setBookmarkExclude(names)}{
#' Set input names to be excluded from bookmarking.
#' }
#' \item{getBookmarkExclude()}{
#' Returns the set of input names to be excluded from bookmarking.
#' }
#' \item{onBookmark(fun)}{
#' Registers a function that will be called just before bookmarking state.
#' }
#' \item{onBookmarked(fun)}{
#' Registers a function that will be called just after bookmarking state.
#' }
#' \item{onRestore(fun)}{
#' Registers a function that will be called when a session is restored, before
#' all other reactives, observers, and render functions are run.
#' }
#' \item{onRestored(fun)}{
#' Registers a function that will be called when a session is restored, after
#' all other reactives, observers, and render functions are run.
#' }
#' \item{doBookmark()}{
#' Do bookmarking and invoke the onBookmark and onBookmarked callback functions.
#' }
#'
#' @name session
NULL
@@ -349,6 +316,7 @@ NULL
#' @return If \code{id} is missing, returns a function that expects an id string
#' as its only argument and returns that id with the namespace prepended.
#' @seealso \url{http://shiny.rstudio.com/articles/modules.html}
#'
#' @export
NS <- function(namespace, id = NULL) {
if (missing(id)) {
@@ -364,7 +332,6 @@ NS <- function(namespace, id = NULL) {
#' @export
ns.sep <- "-"
#' @include utils.R
ShinySession <- R6Class(
'ShinySession',
@@ -378,7 +345,7 @@ ShinySession <- R6Class(
.outputs = list(), # Keeps track of all the output observer objects
.outputOptions = list(), # Options for each of the output observer objects
progressKeys = 'character',
showcase = FALSE,
showcase = 'ANY',
fileUploadContext = 'FileUploadContext',
.input = 'ANY', # Internal ReactiveValues object for normal input sent from client
.clientData = 'ANY', # Internal ReactiveValues object for other data sent from the client
@@ -387,12 +354,6 @@ ShinySession <- R6Class(
flushCallbacks = 'Callbacks',
flushedCallbacks = 'Callbacks',
inputReceivedCallbacks = 'Callbacks',
bookmarkCallbacks = 'Callbacks',
bookmarkedCallbacks = 'Callbacks',
restoreCallbacks = 'Callbacks',
restoredCallbacks = 'Callbacks',
bookmarkExclude = character(0), # Names of inputs to exclude from bookmarking
sendResponse = function(requestMsg, value) {
if (is.null(requestMsg$tag)) {
warning("Tried to send response for untagged message; method: ",
@@ -459,99 +420,9 @@ ShinySession <- R6Class(
# Clear file upload directories, if present
self$onSessionEnded(private$fileUploadContext$rmUploadDirs)
},
createBookmarkObservers = function() {
# This is to be called from the initialization. It registers observers
# for bookmarking to work.
# Get bookmarking config
store <- getShinyOption("bookmarkStore", default = "disable")
if (store == "disable")
return()
# Warn if trying to enable save-to-server bookmarking on a version of SS,
# SSP, or Connect that doesn't support it.
if (store == "server" && inShinyServer() &&
is.null(getShinyOption("save.interface")))
{
showNotification(
"This app tried to enable saved-to-server bookmarking, but it is not supported by the hosting environment.",
duration = NULL, type = "warning", session = self
)
return()
}
withReactiveDomain(self, {
# This observer fires when the bookmark button is clicked.
observeEvent(self$input[["._bookmark_"]], {
self$doBookmark()
})
# If there was an error initializing the current restore context, show
# notification in the client.
observe({
rc <- getCurrentRestoreContext()
if (!is.null(rc$initErrorMessage)) {
showNotification(
paste("Error in RestoreContext initialization:", rc$initErrorMessage),
duration = NULL, type = "error"
)
}
})
# Run the onRestore function at the beginning of the flush cycle, but after
# the server function has been executed.
observe({
if (private$restoreCallbacks$count() > 0) {
tryCatch(
withLogErrors(
isolate({
rc <- getCurrentRestoreContext()
if (rc$active) {
restoreState <- getCurrentRestoreContext()$asList()
private$restoreCallbacks$invoke(restoreState)
}
})
),
error = function(e) {
showNotification(
paste0("Error calling onRestore callback: ", e$message),
duration = NULL, type = "error"
)
}
)
}
}, priority = 1000000)
# Run the onRestored function after the flush cycle completes and information
# is sent to the client.
self$onFlushed(function() {
if (private$restoredCallbacks$count() > 0) {
tryCatch(
withLogErrors(
isolate({
rc <- getCurrentRestoreContext()
if (rc$active) {
restoreState <- getCurrentRestoreContext()$asList()
private$restoredCallbacks$invoke(restoreState)
}
})
),
error = function(e) {
msg <- paste0("Error calling onRestored callback: ", e$message)
showNotification(msg, duration = NULL, type = "error")
}
)
}
})
}) # withReactiveDomain
}
),
public = list(
restoreContext = NULL,
progressStack = 'Stack', # Stack of progress objects
input = 'reactivevalues', # Externally-usable S3 wrapper object for .input
output = 'ANY', # Externally-usable S3 wrapper object for .outputs
@@ -594,12 +465,6 @@ ShinySession <- R6Class(
private$.outputs <- list()
private$.outputOptions <- list()
private$bookmarkCallbacks <- Callbacks$new()
private$bookmarkedCallbacks <- Callbacks$new()
private$restoreCallbacks <- Callbacks$new()
private$restoredCallbacks <- Callbacks$new()
private$createBookmarkObservers()
private$registerSessionEndCallbacks()
if (!is.null(websocket$request$HTTP_SHINY_SERVER_CREDENTIALS)) {
@@ -622,20 +487,10 @@ ShinySession <- R6Class(
)
)
},
rootScope = function() {
self
},
makeScope = function(namespace) {
ns <- NS(namespace)
# Private items for this scope. Can't be part of the scope object because
# `$<-.session_proxy` doesn't allow assignment on overidden names.
bookmarkCallbacks <- Callbacks$new()
restoreCallbacks <- Callbacks$new()
restoredCallbacks <- Callbacks$new()
bookmarkExclude <- character(0)
scope <- createSessionProxy(self,
createSessionProxy(self,
input = .createReactiveValues(private$.input, readonly = TRUE, ns = ns),
output = .createOutputWriter(self, ns = ns),
sendInputMessage = function(inputId, message) {
@@ -647,157 +502,12 @@ ShinySession <- R6Class(
ns = ns,
makeScope = function(namespace) {
self$makeScope(ns(namespace))
},
setBookmarkExclude = function(names) {
bookmarkExclude <<- names
},
getBookmarkExclude = function() {
bookmarkExclude
},
onBookmark = function(fun) {
if (!is.function(fun) || length(fun) != 1) {
stop("`fun` must be a function that takes one argument")
}
bookmarkCallbacks$register(fun)
},
onBookmarked = function(fun) {
stop("onBookmarked() can't be used in a module.")
},
onRestore = function(fun) {
if (!is.function(fun) || length(fun) != 1) {
stop("`fun` must be a function that takes one argument")
}
restoreCallbacks$register(fun)
},
onRestored = function(fun) {
if (!is.function(fun) || length(fun) != 1) {
stop("`fun` must be a function that takes one argument")
}
restoredCallbacks$register(fun)
}
)
# Given a char vector, return a logical vector indicating which of those
# strings are names of things in the namespace.
filterNamespace <- function(x) {
nsString <- paste0(namespace, ns.sep)
substr(x, 1, nchar(nsString)) == nsString
}
# Given a char vector of namespaced names, return a char vector of corresponding
# names with namespace prefix removed.
unNamespace <- function(x) {
if (!all(filterNamespace(x))) {
stop("x contains strings(s) that do not have namespace prefix ", namespace)
}
nsString <- paste0(namespace, ns.sep)
substring(x, nchar(nsString) + 1)
}
# Given a restore state object (a list), return a modified version that's
# scoped to this namespace.
scopeRestoreState <- function(state) {
# State is a list. We need to copy and transform some things for the
# scope.
scopeState <- state
# `values` is an environment and we don't want to modify the original.
scopeState$values <- new.env(parent = emptyenv())
# Keep only inputs that are in the scope, and rename them
scopeState$input <- scopeState$input[filterNamespace(names(scopeState$input))]
names(scopeState$input) <- unNamespace(names(scopeState$input))
# Same for values. This is an environment so we have to handle a little
# differently.
origNames <- names(state$values)
origNames <- origNames[filterNamespace(origNames)]
lapply(origNames, function(origName) {
scopedName <- unNamespace(origName)
scopeState$values[[scopedName]] <- state$values[[origName]]
})
if (!is.null(state$dir)) {
dir <- file.path(state$dir, namespace)
if (dirExists(dir))
scopeState$dir <- dir
}
scopeState
}
# When scope is created, register these bookmarking callbacks on the main
# session object. They will invoke the scope's own callbacks, if any are
# present.
self$onBookmark(function(state) {
# Exit if no user-defined callbacks.
if (bookmarkCallbacks$count() == 0)
return()
scopeState <- ShinySaveState$new(scope$input, scope$getBookmarkExclude())
# Create subdir for this scope
if (!is.null(state$dir)) {
scopeState$dir <- file.path(state$dir, namespace)
res <- dir.create(scopeState$dir)
if (res == FALSE) {
stop("Error creating subdirectory for scope ", namespace)
}
}
# Invoke the callback on the scopeState object
bookmarkCallbacks$invoke(scopeState)
# Copy `values` from scopeState to state, adding namespace
if (length(scopeState$values) != 0) {
if (anyUnnamed(scopeState$values)) {
stop("All scope values in must be named.")
}
lapply(names(scopeState$values), function(origName) {
scopedName <- ns(origName)
state$values[[scopedName]] <- scopeState$values[[origName]]
})
}
})
self$onRestore(function(state) {
# Exit if no user-defined callbacks.
if (restoreCallbacks$count() == 0)
return()
scopeState <- scopeRestoreState(state)
# Invoke user callbacks
restoreCallbacks$invoke(scopeState)
})
self$onRestored(function(state) {
# Exit if no user-defined callbacks.
if (restoredCallbacks$count() == 0)
return()
scopeState <- scopeRestoreState(state)
# Invoke user callbacks
restoredCallbacks$invoke(scopeState)
})
scope
},
ns = function(id) {
NS(NULL, id)
},
# Freeze a value until the flush cycle completes
freezeValue = function(x, name) {
if (!is.reactivevalues(x))
stop("x must be a reactivevalues object")
impl <- .subset2(x, 'impl')
impl$freeze(name)
self$onFlushed(function() impl$thaw(name))
},
onSessionEnded = function(sessionEndedCallback) {
"Registers the given callback to be invoked when the session is closed
(i.e. the connection to the client has been severed). The return value
@@ -830,7 +540,10 @@ ShinySession <- R6Class(
# ..stacktraceon matches with the top-level ..stacktraceoff..
private$closedCallbacks$invoke(onError = printError, ..stacktraceon = TRUE)
flushReact()
flushAllSessions()
lapply(appsByToken$values(), function(shinysession) {
shinysession$flushOutput()
NULL
})
},
isClosed = function() {
return(self$closed)
@@ -955,43 +668,21 @@ ShinySession <- R6Class(
}
},
flushOutput = function() {
if (self$isClosed())
return()
# Return TRUE if there's any stuff to send to the client.
hasPendingUpdates <- function() {
# Even though progressKeys isn't sent to the client, we use it in this
# check. This is because if it is non-empty, sending `values` to the
# client tells it that the flushReact loop is finished, and the client
# then knows to stop showing progress.
return(
length(private$progressKeys) != 0 ||
length(private$invalidatedOutputValues) != 0 ||
length(private$invalidatedOutputErrors) != 0 ||
length(private$inputMessageQueue) != 0
)
}
# ..stacktraceon matches with the top-level ..stacktraceoff..
private$flushCallbacks$invoke(..stacktraceon = TRUE)
# ..stacktraceon matches with the top-level ..stacktraceoff..
on.exit(private$flushedCallbacks$invoke(..stacktraceon = TRUE))
# Schedule execution of onFlushed callbacks
on.exit({
# ..stacktraceon matches with the top-level ..stacktraceoff..
private$flushedCallbacks$invoke(..stacktraceon = TRUE)
# If one of the flushedCallbacks added anything to send to the client,
# or invalidated any observers, set up another flush cycle.
if (hasPendingUpdates() || .getReactiveEnvironment()$hasPendingFlush()) {
scheduleFlush()
}
})
if (!hasPendingUpdates()) {
if (length(private$progressKeys) == 0
&& length(private$invalidatedOutputValues) == 0
&& length(private$invalidatedOutputErrors) == 0
&& length(private$inputMessageQueue) == 0) {
return(invisible())
}
private$progressKeys <- character(0)
values <- private$invalidatedOutputValues
private$invalidatedOutputValues <- Map$new()
errors <- private$invalidatedOutputErrors
@@ -1054,13 +745,6 @@ ShinySession <- R6Class(
private$sendResponse(msg, value)
}
},
sendBinaryMessage = function(type, message) {
typeBytes <- charToRaw(type)
if (length(typeBytes) > 255) {
stop("'type' argument is too long")
}
private$write(c(as.raw(length(typeBytes)), typeBytes, message))
},
sendCustomMessage = function(type, message) {
data <- list()
data[[type]] <- message
@@ -1094,92 +778,9 @@ ShinySession <- R6Class(
return(dereg)
}
},
setBookmarkExclude = function(names) {
private$bookmarkExclude <- names
},
getBookmarkExclude = function() {
private$bookmarkExclude
},
onBookmark = function(fun) {
if (!is.function(fun) || length(fun) != 1) {
stop("`fun` must be a function that takes one argument")
}
private$bookmarkCallbacks$register(fun)
},
onBookmarked = function(fun) {
if (!is.function(fun) || length(fun) != 1) {
stop("`fun` must be a function that takes one argument")
}
private$bookmarkedCallbacks$register(fun)
},
onRestore = function(fun) {
if (!is.function(fun) || length(fun) != 1) {
stop("`fun` must be a function that takes one argument")
}
private$restoreCallbacks$register(fun)
},
onRestored = function(fun) {
if (!is.function(fun) || length(fun) != 1) {
stop("`fun` must be a function that takes one argument")
}
private$restoredCallbacks$register(fun)
},
doBookmark = function() {
# Get bookmarking store config
store <- getShinyOption("bookmarkStore", default = "disable")
if (store == "disable")
return()
tryCatch(
withLogErrors({
saveState <- ShinySaveState$new(
input = self$input,
exclude = self$getBookmarkExclude(),
onSave = function(state) {
private$bookmarkCallbacks$invoke(state)
}
)
if (store == "server") {
url <- saveShinySaveState(saveState)
} else if (store == "url") {
url <- encodeShinySaveState(saveState)
} else {
stop("Unknown store type: ", store)
}
clientData <- self$clientData
url <- paste0(
clientData$url_protocol, "//",
clientData$url_hostname,
if (nzchar(clientData$url_port)) paste0(":", clientData$url_port),
clientData$url_pathname,
"?", url
)
# If onBookmarked callback was provided, invoke it; if not call
# the default.
if (private$bookmarkedCallbacks$count() > 0) {
private$bookmarkedCallbacks$invoke(url)
} else {
showBookmarkUrlModal(url)
}
}),
error = function(e) {
msg <- paste0("Error bookmarking state: ", e$message)
showNotification(msg, duration = NULL, type = "error")
}
)
},
reactlog = function(logEntry) {
# Use sendCustomMessage instead of sendMessage, because the handler in
# shiny-showcase.js only has access to public API of the Shiny object.
if (private$showcase)
self$sendCustomMessage("reactlog", logEntry)
private$sendMessage(reactlog = logEntry)
},
reload = function() {
private$sendMessage(reload = TRUE)
@@ -1202,9 +803,6 @@ ShinySession <- R6Class(
)
)
},
updateQueryString = function(queryString) {
private$sendMessage(updateQueryString = list(queryString = queryString))
},
resetBrush = function(brushId) {
private$sendMessage(
resetBrush = list(
@@ -1238,9 +836,6 @@ ShinySession <- R6Class(
`@uploadEnd` = function(jobId, inputId) {
fileData <- private$fileUploadContext$getUploadOperation(jobId)$finish()
private$.input$set(inputId, fileData)
private$.input$setMeta(inputId, "shiny.serializer", serializerFileInput)
invisible()
},
# Provides a mechanism for handling direct HTTP requests that are posted
@@ -1352,10 +947,6 @@ ShinySession <- R6Class(
unlink(tmpdata)
stop(attr(result, "condition", exact = TRUE))
}
if (!file.exists(tmpdata)) {
# If no file was created, return a 404
return(httpResponse(404, content = "404 Not found"))
}
return(httpResponse(
200,
download$contentType %OR% getContentType(filename),
@@ -1426,11 +1017,10 @@ ShinySession <- R6Class(
registerDataObj = function(name, data, filterFunc) {
# abusing downloads at the moment
self$downloads$set(name, list(data = data, filter = filterFunc))
return(sprintf('session/%s/dataobj/%s?w=%s&nonce=%s',
return(sprintf('session/%s/dataobj/%s?w=%s',
URLencode(self$token, TRUE),
URLencode(name, TRUE),
workerId(),
URLencode(createUniqueId(8), TRUE)))
workerId()))
},
# This function suspends observers for hidden outputs and resumes observers
# for un-hidden outputs.
@@ -1608,60 +1198,3 @@ outputOptions <- function(x, name, ...) {
.subset2(x, 'impl')$outputOptions(name, ...)
}
#' Add callbacks for Shiny session events
#'
#' These functions are for registering callbacks on Shiny session events.
#' \code{onFlush} registers a function that will be called before Shiny flushes
#' the reactive system. \code{onFlushed} registers a function that will be
#' called after Shiny flushes the reactive system. \code{onSessionEnded}
#' registers a function to be called after the client has disconnected.
#'
#' These functions should be called within the application's server function.
#'
#' All of these functions return a function which can be called with no
#' arguments to cancel the registration.
#'
#' @param fun A callback function.
#' @param once Should the function be run once, and then cleared, or should it
#' re-run each time the event occurs. (Only for \code{onFlush} and
#' \code{onFlushed}.)
#' @param session A shiny session object.
#'
#' @export
onFlush <- function(fun, once = TRUE, session = getDefaultReactiveDomain()) {
session$onFlush(fun, once = once)
}
#' @rdname onFlush
#' @export
onFlushed <- function(fun, once = TRUE, session = getDefaultReactiveDomain()) {
session$onFlushed(fun, once = once)
}
#' @rdname onFlush
#' @export
onSessionEnded <- function(fun, session = getDefaultReactiveDomain()) {
session$onSessionEnded(fun)
}
scheduleFlush <- function() {
timerCallbacks$schedule(0, function() {})
}
flushAllSessions <- function() {
lapply(appsByToken$values(), function(shinysession) {
tryCatch(
shinysession$flushOutput(),
stop = function(e) {
# If there are any uncaught errors that bubbled up to here, close the
# session.
shinysession$close()
}
)
NULL
})
}

View File

@@ -44,7 +44,7 @@ renderPage <- function(ui, connection, showcase=0) {
shiny_deps <- list(
htmlDependency("json2", "2014.02.04", c(href="shared"), script = "json2-min.js"),
htmlDependency("jquery", "1.12.4", c(href="shared"), script = "jquery.min.js"),
htmlDependency("jquery", "1.11.3", c(href="shared"), script = "jquery.min.js"),
htmlDependency("babel-polyfill", "6.7.2", c(href="shared"), script = "babel-polyfill.min.js"),
htmlDependency("shiny", utils::packageVersion("shiny"), c(href="shared"),
script = if (getOption("shiny.minified", TRUE)) "shiny.min.js" else "shiny.js",
@@ -64,6 +64,7 @@ renderPage <- function(ui, connection, showcase=0) {
#'
#' @param ui A user interace definition
#' @return The user interface definition, without modifications or side effects.
#'
#' @export
shinyUI <- function(ui) {
.globals$ui <- list(ui)
@@ -90,34 +91,17 @@ uiHttpHandler <- function(ui, uiPattern = "^/$") {
if (!is.null(mode))
showcaseMode <- mode
}
# Create a restore context using query string
bookmarkStore <- getShinyOption("bookmarkStore", default = "disable")
if (bookmarkStore == "disable") {
# If bookmarking is disabled, use empty context
restoreContext <- RestoreContext$new()
} else {
restoreContext <- RestoreContext$new(req$QUERY_STRING)
}
withRestoreContext(restoreContext, {
uiValue <- NULL
if (is.function(ui)) {
if (length(formals(ui)) > 0) {
# No corresponding ..stacktraceoff.., this is pure user code
uiValue <- ..stacktraceon..(ui(req))
} else {
# No corresponding ..stacktraceoff.., this is pure user code
uiValue <- ..stacktraceon..(ui())
}
uiValue <- if (is.function(ui)) {
if (length(formals(ui)) > 0) {
# No corresponding ..stacktraceoff.., this is pure user code
..stacktraceon..(ui(req))
} else {
if (getCurrentRestoreContext()$active) {
warning("Trying to restore saved app state, but UI code must be a function for this to work! See ?enableBookmarking")
}
uiValue <- ui
# No corresponding ..stacktraceoff.., this is pure user code
..stacktraceon..(ui())
}
})
} else {
ui
}
if (is.null(uiValue))
return(NULL)

View File

@@ -19,6 +19,7 @@ globalVariables('func')
#' dynamically generated UIs, such as those created by Shiny code snippets
#' embedded in R Markdown documents).
#' @return The \code{renderFunc} function, with annotations.
#'
#' @export
markRenderFunction <- function(uiFunc, renderFunc, outputArgs = list()) {
# a mutable object that keeps track of whether `useRenderFunction` has been
@@ -247,6 +248,7 @@ renderImage <- function(expr, env=parent.frame(), quoted=FALSE,
#' function, instead of the printed output.
#'
#' @example res/text-example.R
#'
#' @export
renderPrint <- function(expr, env = parent.frame(), quoted = FALSE,
width = getOption('width'), outputArgs=list()) {
@@ -287,6 +289,7 @@ renderPrint <- function(expr, env = parent.frame(), quoted = FALSE,
#' function, rather than the returned text value.
#'
#' @example res/text-example.R
#'
#' @export
renderText <- function(expr, env=parent.frame(), quoted=FALSE,
outputArgs=list()) {
@@ -318,6 +321,7 @@ renderText <- function(expr, env=parent.frame(), quoted=FALSE,
#' interactive R Markdown document.
#'
#' @seealso conditionalPanel
#'
#' @export
#' @examples
#' ## Only run examples in interactive R sessions

View File

@@ -31,7 +31,7 @@ licenseLink <- function(licenseName) {
showcaseHead <- function() {
deps <- list(
htmlDependency("jqueryui", "1.12.1", c(href="shared/jqueryui"),
htmlDependency("jqueryui", "1.11.4", c(href="shared/jqueryui"),
script = "jquery-ui.min.js"),
htmlDependency("showdown", "0.3.1", c(href="shared/showdown/compressed"),
script = "showdown.js"),

View File

@@ -22,11 +22,6 @@ TimerCallbacks <- R6Class(
.times <<- data.frame()
},
schedule = function(millis, func) {
# If args could fail to evaluate, let's make them do that before
# we change any state
force(millis)
force(func)
id <- .nextId
.nextId <<- .nextId + 1L
@@ -61,7 +56,7 @@ TimerCallbacks <- R6Class(
},
executeElapsed = function() {
elapsed <- takeElapsed()
if (nrow(elapsed) == 0)
if (length(elapsed) == 0)
return(FALSE)
for (id in elapsed$id) {

View File

@@ -39,44 +39,6 @@ updateTextInput <- function(session, inputId, label = NULL, value = NULL) {
session$sendInputMessage(inputId, message)
}
#' Change the value of a textarea input on the client
#'
#' @template update-input
#' @param value The value to set for the input object.
#'
#' @seealso \code{\link{textAreaInput}}
#'
#' @examples
#' ## Only run examples in interactive R sessions
#' if (interactive()) {
#'
#' ui <- fluidPage(
#' sliderInput("controller", "Controller", 0, 20, 10),
#' textAreaInput("inText", "Input textarea"),
#' textAreaInput("inText2", "Input textarea 2")
#' )
#'
#' server <- function(input, output, session) {
#' observe({
#' # We'll use the input$controller variable multiple times, so save it as x
#' # for convenience.
#' x <- input$controller
#'
#' # This will change the value of input$inText, based on x
#' updateTextAreaInput(session, "inText", value = paste("New text", x))
#'
#' # Can also set the label, this time for input$inText2
#' updateTextAreaInput(session, "inText2",
#' label = paste("New label", x),
#' value = paste("New text", x))
#' })
#' }
#'
#' shinyApp(ui, server)
#' }
#' @export
updateTextAreaInput <- updateTextInput
#' Change the value of a checkbox input on the client
#'
@@ -166,7 +128,7 @@ updateActionButton <- function(session, inputId, label = NULL, icon = NULL) {
#'
#' @template update-input
#' @param value The desired date value. Either a Date object, or a string in
#' \code{yyyy-mm-dd} format. Supply \code{NA} to clear the date.
#' \code{yyyy-mm-dd} format.
#' @param min The minimum allowed date. Either a Date object, or a string in
#' \code{yyyy-mm-dd} format.
#' @param max The maximum allowed date. Either a Date object, or a string in
@@ -179,18 +141,21 @@ updateActionButton <- function(session, inputId, label = NULL, icon = NULL) {
#' if (interactive()) {
#'
#' ui <- fluidPage(
#' sliderInput("n", "Day of month", 1, 30, 10),
#' sliderInput("controller", "Controller", 1, 30, 10),
#' dateInput("inDate", "Input date")
#' )
#'
#' server <- function(input, output, session) {
#' observe({
#' date <- as.Date(paste0("2013-04-", input$n))
#' # We'll use the input$controller variable multiple times, so save it as x
#' # for convenience.
#' x <- input$controller
#'
#' updateDateInput(session, "inDate",
#' label = paste("Date label", input$n),
#' value = date,
#' min = date - 3,
#' max = date + 3
#' label = paste("Date label", x),
#' value = paste("2013-04-", x, sep=""),
#' min = paste("2013-04-", x-1, sep=""),
#' max = paste("2013-04-", x+1, sep="")
#' )
#' })
#' }
@@ -201,18 +166,11 @@ updateActionButton <- function(session, inputId, label = NULL, icon = NULL) {
updateDateInput <- function(session, inputId, label = NULL, value = NULL,
min = NULL, max = NULL) {
# Make sure values are NULL or Date objects. This is so we can ensure that
# they will be formatted correctly. For example, the string "2016-08-9" is not
# correctly formatted, but the conversion to Date and back to string will fix
# it.
formatDate <- function(x) {
if (is.null(x))
return(NULL)
format(as.Date(x), "%Y-%m-%d")
}
value <- formatDate(value)
min <- formatDate(min)
max <- formatDate(max)
# If value is a date object, convert it to a string with yyyy-mm-dd format
# Same for min and max
if (inherits(value, "Date")) value <- format(value, "%Y-%m-%d")
if (inherits(min, "Date")) min <- format(min, "%Y-%m-%d")
if (inherits(max, "Date")) max <- format(max, "%Y-%m-%d")
message <- dropNulls(list(label=label, value=value, min=min, max=max))
session$sendInputMessage(inputId, message)
@@ -223,9 +181,9 @@ updateDateInput <- function(session, inputId, label = NULL, value = NULL,
#'
#' @template update-input
#' @param start The start date. Either a Date object, or a string in
#' \code{yyyy-mm-dd} format. Supplying \code{NA} clears the start date.
#' \code{yyyy-mm-dd} format.
#' @param end The end date. Either a Date object, or a string in
#' \code{yyyy-mm-dd} format. Supplying \code{NA} clears the end date.
#' \code{yyyy-mm-dd} format.
#' @param min The minimum allowed date. Either a Date object, or a string in
#' \code{yyyy-mm-dd} format.
#' @param max The maximum allowed date. Either a Date object, or a string in
@@ -238,20 +196,20 @@ updateDateInput <- function(session, inputId, label = NULL, value = NULL,
#' if (interactive()) {
#'
#' ui <- fluidPage(
#' sliderInput("n", "Day of month", 1, 30, 10),
#' sliderInput("controller", "Controller", 1, 30, 10),
#' dateRangeInput("inDateRange", "Input date range")
#' )
#'
#' server <- function(input, output, session) {
#' observe({
#' date <- as.Date(paste0("2013-04-", input$n))
#' # We'll use the input$controller variable multiple times, so save it as x
#' # for convenience.
#' x <- input$controller
#'
#' updateDateRangeInput(session, "inDateRange",
#' label = paste("Date range label", input$n),
#' start = date - 1,
#' end = date + 1,
#' min = date - 5,
#' max = date + 5
#' label = paste("Date range label", x),
#' start = paste("2013-01-", x, sep=""),
#' end = paste("2013-12-", x, sep="")
#' )
#' })
#' }
@@ -271,7 +229,7 @@ updateDateRangeInput <- function(session, inputId, label = NULL,
message <- dropNulls(list(
label = label,
value = dropNulls(list(start = start, end = end)),
value = c(start, end),
min = min,
max = max
))
@@ -457,11 +415,11 @@ updateInputOptions <- function(session, inputId, label = NULL, choices = NULL,
if (!is.null(choices))
choices <- choicesWithNames(choices)
if (!is.null(selected))
selected <- validateSelected(selected, choices, session$ns(inputId))
selected <- validateSelected(selected, choices, inputId)
options <- if (!is.null(choices)) {
format(tagList(
generateOptions(session$ns(inputId), choices, selected, inline, type = type)
generateOptions(inputId, choices, selected, inline, type = type)
))
}

219
R/utils.R
View File

@@ -23,6 +23,7 @@ NULL
#' rnormA(3) # [1] 1.8285879 -0.7468041 -0.4639111
#' rnormA(5) # [1] 1.8285879 -0.7468041 -0.4639111 -1.6510126 -1.4686924
#' rnormB(5) # [1] -0.7946034 0.2568374 -0.6567597 1.2451387 -0.8375699
#'
#' @export
repeatable <- function(rngfunc, seed = stats::runif(1, 0, .Machine$integer.max)) {
force(seed)
@@ -119,6 +120,16 @@ p_randomInt <- function(...) {
withPrivateSeed(randomInt(...))
}
# Return a random hexadecimal string with `length` digits.
randomID <- function(length = 16) {
paste(sample(
c("0", "1", "2", "3", "4", "5", "6", "7", "8","9",
"a", "b", "c", "d", "e", "f"),
length,
replace = TRUE
), collapse = '')
}
isWholeNum <- function(x, tol = .Machine$double.eps^0.5) {
abs(x - round(x)) < tol
}
@@ -182,21 +193,6 @@ anyUnnamed <- function(x) {
any(!nzchar(nms))
}
# Given two named vectors, join them together, and keep only the last element
# with a given name in the resulting vector. If b has any elements with the same
# name as elements in a, the element in a is dropped. Also, if there are any
# duplicated names in a or b, only the last one with that name is kept.
mergeVectors <- function(a, b) {
if (anyUnnamed(a) || anyUnnamed(b)) {
stop("Vectors must be either NULL or have names for all elements")
}
x <- c(a, b)
drop_idx <- duplicated(names(x), fromLast = TRUE)
x[!drop_idx]
}
# Combine dir and (file)name into a file path. If a file already exists with a
# name differing only by case, then use it instead.
file.path.ci <- function(...) {
@@ -239,12 +235,6 @@ find.file.ci <- function(...) {
return(matches[1])
}
# The function base::dir.exists was added in R 3.2.0, but for backward
# compatibility we need to add this function
dirExists <- function(paths) {
file.exists(paths) & file.info(paths)$isdir
}
# Attempt to join a path and relative path, and turn the result into a
# (normalized) absolute path. The result will only be returned if it is an
# existing file/directory and is a descendant of dir.
@@ -410,6 +400,7 @@ makeFunction <- function(args = pairlist(), body, env = parent.frame()) {
#'
#' isolate(tripleA())
#' # "text, text, text"
#'
#' @export
exprToFunction <- function(expr, env=parent.frame(), quoted=FALSE) {
if (!quoted) {
@@ -443,6 +434,7 @@ exprToFunction <- function(expr, env=parent.frame(), quoted=FALSE) {
#' the name of the calling function.
#' @param wrappedWithLabel,..stacktraceon Advanced use only. For stack manipulation purposes; see
#' \code{\link{stacktrace}}.
#'
#' @export
installExprFunction <- function(expr, name, eval.env = parent.frame(2),
quoted = FALSE,
@@ -514,8 +506,6 @@ parseQueryString <- function(str, nested = FALSE) {
str <- substr(str, 2, nchar(str))
pairs <- strsplit(str, '&', fixed = TRUE)[[1]]
# Drop any empty items (if there's leading/trailing/consecutive '&' chars)
pairs <- pairs[pairs != ""]
pairs <- strsplit(pairs, '=', fixed = TRUE)
keys <- vapply(pairs, function(x) x[1], FUN.VALUE = character(1))
@@ -563,7 +553,13 @@ shinyCallingHandlers <- function(expr) {
return()
handle <- getOption('shiny.error')
if (is.function(handle)) handle()
if (is.function(handle)) {
if ("condition" %in% names(formals(handle))) {
handle(condition = e)
} else {
handle()
}
}
}
)
}
@@ -980,62 +976,6 @@ safeError <- function(error) {
error
}
#***********************************************************************#
#**** Keep this function internal for now, may chnage in the future ****#
#***********************************************************************#
# #' Propagate an error through Shiny, but catch it before it throws
# #'
# #' Throws a type of exception that is caught by observers. When such an
# #' exception is triggered, all reactive links are broken. So, essentially,
# #' \code{reactiveStop()} behaves just like \code{stop()}, except that
# #' instead of ending the session, it is silently swalowed by Shiny.
# #'
# #' This function should be used when you want to disrupt the reactive
# #' links in a reactive chain, but do not want to end the session. For
# #' example, this enables you to disallow certain inputs, but get back
# #' to business as usual when valid inputs are re-entered.
# #' \code{reactiveStop} is also called internally by Shiny to create
# #' special errors, such as the ones generated by \code{\link{validate}()},
# #' \code{\link{req}()} and \code{\link{cancelOutput}()}.
# #'
# #' @param message An optional error message.
# #' @param class An optional class to add to the error.
# #' @export
# #' @examples
# #' ## Note: the breaking of the reactive chain that happens in the app
# #' ## below (when input$txt = 'bad' and input$allowBad = 'FALSE') is
# #' ## easily visualized with `showReactLog()`
# #'
# #' ## Only run examples in interactive R sessions
# #' if (interactive()) {
# #'
# #' ui <- fluidPage(
# #' textInput('txt', 'Enter some text...'),
# #' selectInput('allowBad', 'Allow the string \'bad\'?',
# #' c('TRUE', 'FALSE'), selected = 'FALSE')
# #' )
# #'
# #' server <- function(input, output) {
# #' val <- reactive({
# #' if (!(as.logical(input$allowBad))) {
# #' if (identical(input$txt, "bad")) {
# #' reactiveStop()
# #' }
# #' }
## ' })
# #'
# #' observe({
# #' val()
# #' })
# #' }
# #'
# #' shinyApp(ui, server)
# #' }
# #' @export
reactiveStop <- function(message = "", class = NULL) {
stopWithCondition(c("shiny.silent.error", class), message)
}
#' Validate input values and other conditions
#'
#' For an output rendering function (e.g. \code{\link{renderPlot}()}), you may
@@ -1092,16 +1032,15 @@ reactiveStop <- function(message = "", class = NULL) {
#' \code{shiny-output-error-} prepended to this value.
#' @export
#' @examples
#' ## Only run examples in interactive R sessions
#' if (interactive()) {
#'
#' ui <- fluidPage(
#' # in ui.R
#' fluidPage(
#' checkboxGroupInput('in1', 'Check some letters', choices = head(LETTERS)),
#' selectizeInput('in2', 'Select a state', choices = state.name),
#' plotOutput('plot')
#' )
#'
#' server <- function(input, output) {
#' # in server.R
#' function(input, output) {
#' output$plot <- renderPlot({
#' validate(
#' need(input$in1, 'Check at least one letter!'),
@@ -1110,10 +1049,6 @@ reactiveStop <- function(message = "", class = NULL) {
#' plot(1:10, main = paste(c(input$in1, input$in2), collapse = ', '))
#' })
#' }
#'
#' shinyApp(ui, server)
#'
#' }
validate <- function(..., errorClass = character(0)) {
results <- sapply(list(...), function(x) {
# Detect NULL or NA
@@ -1134,7 +1069,8 @@ validate <- function(..., errorClass = character(0)) {
# There may be empty strings remaining; these are message-less failures that
# started as FALSE
results <- results[nzchar(results)]
reactiveStop(paste(results, collapse="\n"), c(errorClass, "validation"))
stopWithCondition(c("validation", "shiny.silent.error", errorClass),
paste(results, collapse="\n"))
}
#' @param expr An expression to test. The condition will pass if the expression
@@ -1228,67 +1164,20 @@ need <- function(expr, message = paste(label, "must be provided"), label) {
#'
#' \code{req(input$a != 0)}
#'
#' \strong{Using \code{req(FALSE)}}
#'
#' You can use \code{req(FALSE)} (i.e. no condition) if you've already performed
#' all the checks you needed to by that point and just want to stop the reactive
#' chain now. There is no advantange to this, except perhaps ease of readibility
#' if you have a complicated condition to check for (or perhaps if you'd like to
#' divide your condition into nested \code{if} statements).
#'
#' \strong{Using \code{cancelOutput = TRUE}}
#'
#' When \code{req(..., cancelOutput = TRUE)} is used, the "silent" exception is
#' also raised, but it is treated slightly differently if one or more outputs are
#' currently being evaluated. In those cases, the reactive chain does not proceed
#' or update, but the output(s) are left is whatever state they happen to be in
#' (whatever was their last valid state).
#'
#' Note that this is always going to be the case if
#' this is used inside an output context (e.g. \code{output$txt <- ...}). It may
#' or may not be the case if it is used inside a non-output context (e.g.
#' \code{\link{reactive}}, \code{\link{observe}} or \code{\link{observeEvent}})
#' -- depending on whether or not there is an \code{output$...} that is triggered
#' as a result of those calls. See the examples below for concrete scenarios.
#'
#' @param ... Values to check for truthiness.
#' @param cancelOutput If \code{TRUE} and an output is being evaluated, stop
#' processing as usual but instead of clearing the output, leave it in
#' whatever state it happens to be in.
#' @param x An expression whose truthiness value we want to determine
#' @return The first value that was passed in.
#'
#' @export
#' @examples
#' ## Only run examples in interactive R sessions
#' if (interactive()) {
#' ui <- fluidPage(
#' textInput('data', 'Enter a dataset from the "datasets" package', 'cars'),
#' p('(E.g. "cars", "mtcars", "pressure", "faithful")'), hr(),
#' tableOutput('tbl')
#' )
#'
#' server <- function(input, output) {
#' output$tbl <- renderTable({
#'
#' ## to require that the user types something, use: `req(input$data)`
#' ## but better: require that input$data is valid and leave the last
#' ## valid table up
#' req(exists(input$data, "package:datasets", inherits = FALSE),
#' cancelOutput = TRUE)
#'
#' head(get(input$data, "package:datasets", inherits = FALSE))
#' })
#' }
#'
#' shinyApp(ui, server)
#' }
req <- function(..., cancelOutput = FALSE) {
dotloop(function(item) {
if (!isTruthy(item)) {
if (isTRUE(cancelOutput)) {
cancelOutput()
} else {
reactiveStop(class = "validation")
stopWithCondition(c("validation", "shiny.silent.error"), "")
}
}
}, ...)
@@ -1299,44 +1188,20 @@ req <- function(..., cancelOutput = FALSE) {
invisible()
}
#***********************************************************************#
#**** Keep this function internal for now, may chnage in the future ****#
#***********************************************************************#
# #' Cancel processing of the current output
# #'
# #' Signals an error that Shiny treats specially if an output is currently being
# #' evaluated. Execution will stop, but rather than clearing the output (as
# #' \code{\link{req}} does) or showing an error message (as \code{\link{stop}}
# #' does), the output simply remains unchanged.
# #'
# #' If \code{cancelOutput} is called in any non-output context (like in an
# #' \code{\link{observe}} or \code{\link{observeEvent}}), the effect is the same
# #' as \code{\link{req}(FALSE)}.
# #' @export
# #' @examples
# #' ## Only run examples in interactive R sessions
# #' if (interactive()) {
# #'
# #' # uncomment the desired line to experiment with cancelOutput() vs. req()
# #'
# #' ui <- fluidPage(
# #' textInput('txt', 'Enter text'),
# #' textOutput('check')
# #' )
# #'
# #' server <- function(input, output) {
# #' output$check <- renderText({
# #' # req(input$txt)
# #' if (input$txt == 'hi') return('hi')
# #' else if (input$txt == 'bye') return('bye')
# #' # else cancelOutput()
# #' })
# #' }
# #'
# #' shinyApp(ui, server)
# #' }
#' Cancel processing of the current output
#'
#' Signals an error that Shiny treats specially if an output is currently being
#' evaluated. Execution will stop, but rather than clearing the output (as
#' \code{\link{req}} does) or showing an error message (as \code{\link{stop}}
#' does), the output simply remains unchanged.
#'
#' If \code{cancelOutput} is called in any non-output context (like in an
#' \code{\link{observe}} or \code{\link{observeEvent}}), the effect is the same
#' as \code{\link{req}(FALSE)}.
#'
#' @export
cancelOutput <- function() {
reactiveStop(class = "shiny.output.cancel")
stopWithCondition(c("shiny.output.cancel", "shiny.silent.error"), "")
}
# Execute a function against each element of ..., but only evaluate each element
@@ -1351,8 +1216,6 @@ dotloop <- function(fun_, ...) {
invisible()
}
#' @export
#' @rdname req
isTruthy <- function(x) {
if (inherits(x, 'try-error'))
return(FALSE)

View File

@@ -1,8 +1,6 @@
# Shiny
*Travis:* [![Travis Build Status](https://travis-ci.org/rstudio/shiny.svg?branch=master)](https://travis-ci.org/rstudio/shiny)
*AppVeyor:* [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/rstudio/shiny?branch=master&svg=true)](https://ci.appveyor.com/project/rstudio/shiny)
[![Build Status](https://travis-ci.org/rstudio/shiny.svg?branch=master)](https://travis-ci.org/rstudio/shiny)
Shiny is a new package from RStudio that makes it incredibly easy to build interactive web applications with R.

View File

@@ -1,45 +0,0 @@
# DO NOT CHANGE the "init" and "install" sections below
# Download script file from GitHub
init:
ps: |
$ErrorActionPreference = "Stop"
Invoke-WebRequest http://raw.github.com/krlmlr/r-appveyor/master/scripts/appveyor-tool.ps1 -OutFile "..\appveyor-tool.ps1"
Import-Module '..\appveyor-tool.ps1'
install:
ps: Bootstrap
cache:
- C:\RLibrary
# Adapt as necessary starting from here
build_script:
- travis-tool.sh install_deps
test_script:
- travis-tool.sh run_tests
on_failure:
- 7z a failure.zip *.Rcheck\*
- appveyor PushArtifact failure.zip
artifacts:
- path: '*.Rcheck\**\*.log'
name: Logs
- path: '*.Rcheck\**\*.out'
name: Logs
- path: '*.Rcheck\**\*.fail'
name: Logs
- path: '*.Rcheck\**\*.Rout'
name: Logs
- path: '\*_*.tar.gz'
name: Bits
- path: '\*_*.zip'
name: Bits

View File

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

View File

@@ -44,9 +44,7 @@ sd_section("UI Inputs",
"sliderInput",
"submitButton",
"textInput",
"textAreaInput",
"passwordInput",
"modalButton",
"updateActionButton",
"updateCheckboxGroupInput",
"updateCheckboxInput",
@@ -57,9 +55,7 @@ sd_section("UI Inputs",
"updateSelectInput",
"updateSliderInput",
"updateTabsetPanel",
"updateTextInput",
"updateTextAreaInput",
"updateQueryString"
"updateTextInput"
)
)
sd_section("UI Outputs",
@@ -73,11 +69,7 @@ sd_section("UI Outputs",
"verbatimTextOutput",
"downloadButton",
"Progress",
"withProgress",
"modalDialog",
"urlModal",
"showModal",
"showNotification"
"withProgress"
)
)
sd_section("Interface builder functions",
@@ -92,9 +84,7 @@ sd_section("Interface builder functions",
"withTags",
"htmlTemplate",
"bootstrapLib",
"suppressDependencies",
"insertUI",
"removeUI"
"suppressDependencies"
)
)
sd_section("Rendering functions",
@@ -130,7 +120,6 @@ sd_section("Reactive constructs",
"reactiveTimer",
"reactiveValues",
"reactiveValuesToList",
"freezeReactiveValue",
"domains",
"showReactLog"
)
@@ -154,16 +143,6 @@ sd_section("Running",
"viewer"
)
)
sd_section("Bookmarking state",
"Functions that are used for bookmarking and restoring state.",
c(
"bookmarkButton",
"enableBookmarking",
"setBookmarkExclude",
"showBookmarkUrlModal",
"onBookmark"
)
)
sd_section("Extending Shiny",
"Functions that are intended to be called by third-party packages that extend Shiny.",
c(
@@ -178,13 +157,9 @@ sd_section("Utility functions",
"Miscellaneous utilities that may be useful to advanced users or when extending Shiny.",
c(
"req",
"cancelOutput",
"validate",
"session",
"shinyOptions",
"safeError",
"onFlush",
"restoreInput",
"applyInputHandlers",
"exprToFunction",
"installExprFunction",
"parseQueryString",

View File

@@ -66,7 +66,7 @@ svg {
}
.node path {
fill: white;
stroke: #999;
stroke: #777;
stroke-width: 7.5px;
transition: fill 0.75s ease;
}
@@ -83,9 +83,6 @@ svg {
.node.running path {
fill: #61B97E;
}
.node.fixed path {
stroke: #000;
}
#legend {
font-size: 22px;
position: fixed;
@@ -1097,13 +1094,7 @@ function update() {
.on('mouseout', function(d, i) {
$('#description').text('');
})
.on('dblclick', function(d) {
d3.event.stopPropagation();
d3.select(this).classed('fixed', d.fixed = false);
})
.call(force.drag().on('dragstart', function(d) {
d3.select(this).classed('fixed', d.fixed = true);
}));
.call(force.drag);
newG.append('path')
.attr('transform', 'scale(0.08)')
.attr('stroke', 'black')

View File

@@ -1,6 +1,6 @@
/*!
* Bootstrap v3.3.7 (http://getbootstrap.com)
* Copyright 2011-2016 Twitter, Inc.
* Bootstrap v3.3.6 (http://getbootstrap.com)
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
.btn-default,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
/*!
* Bootstrap v3.3.7 (http://getbootstrap.com)
* Copyright 2011-2016 Twitter, Inc.
* Bootstrap v3.3.6 (http://getbootstrap.com)
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
@@ -1106,6 +1106,7 @@ a:focus {
text-decoration: underline;
}
a:focus {
outline: thin dotted;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
@@ -2536,6 +2537,7 @@ select[size] {
input[type="file"]:focus,
input[type="radio"]:focus,
input[type="checkbox"]:focus {
outline: thin dotted;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
@@ -3027,6 +3029,7 @@ select[multiple].input-lg {
.btn.focus,
.btn:active.focus,
.btn.active.focus {
outline: thin dotted;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
/*!
* Bootstrap v3.3.7 (http://getbootstrap.com)
* Copyright 2011-2016 Twitter, Inc.
* Bootstrap v3.3.6 (http://getbootstrap.com)
* Copyright 2011-2015 Twitter, Inc.
* Licensed under the MIT license
*/
@@ -11,16 +11,16 @@ if (typeof jQuery === 'undefined') {
+function ($) {
'use strict';
var version = $.fn.jquery.split(' ')[0].split('.')
if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 3)) {
throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4')
if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 2)) {
throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3')
}
}(jQuery);
/* ========================================================================
* Bootstrap: transition.js v3.3.7
* Bootstrap: transition.js v3.3.6
* http://getbootstrap.com/javascript/#transitions
* ========================================================================
* Copyright 2011-2016 Twitter, Inc.
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
@@ -77,10 +77,10 @@ if (typeof jQuery === 'undefined') {
}(jQuery);
/* ========================================================================
* Bootstrap: alert.js v3.3.7
* Bootstrap: alert.js v3.3.6
* http://getbootstrap.com/javascript/#alerts
* ========================================================================
* Copyright 2011-2016 Twitter, Inc.
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
@@ -96,7 +96,7 @@ if (typeof jQuery === 'undefined') {
$(el).on('click', dismiss, this.close)
}
Alert.VERSION = '3.3.7'
Alert.VERSION = '3.3.6'
Alert.TRANSITION_DURATION = 150
@@ -109,7 +109,7 @@ if (typeof jQuery === 'undefined') {
selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
}
var $parent = $(selector === '#' ? [] : selector)
var $parent = $(selector)
if (e) e.preventDefault()
@@ -172,10 +172,10 @@ if (typeof jQuery === 'undefined') {
}(jQuery);
/* ========================================================================
* Bootstrap: button.js v3.3.7
* Bootstrap: button.js v3.3.6
* http://getbootstrap.com/javascript/#buttons
* ========================================================================
* Copyright 2011-2016 Twitter, Inc.
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
@@ -192,7 +192,7 @@ if (typeof jQuery === 'undefined') {
this.isLoading = false
}
Button.VERSION = '3.3.7'
Button.VERSION = '3.3.6'
Button.DEFAULTS = {
loadingText: 'loading...'
@@ -214,10 +214,10 @@ if (typeof jQuery === 'undefined') {
if (state == 'loadingText') {
this.isLoading = true
$el.addClass(d).attr(d, d).prop(d, true)
$el.addClass(d).attr(d, d)
} else if (this.isLoading) {
this.isLoading = false
$el.removeClass(d).removeAttr(d).prop(d, false)
$el.removeClass(d).removeAttr(d)
}
}, this), 0)
}
@@ -281,15 +281,10 @@ if (typeof jQuery === 'undefined') {
$(document)
.on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
var $btn = $(e.target).closest('.btn')
var $btn = $(e.target)
if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
Plugin.call($btn, 'toggle')
if (!($(e.target).is('input[type="radio"], input[type="checkbox"]'))) {
// Prevent double click on radios, and the double selections (so cancellation) on checkboxes
e.preventDefault()
// The target component still receive the focus
if ($btn.is('input,button')) $btn.trigger('focus')
else $btn.find('input:visible,button:visible').first().trigger('focus')
}
if (!($(e.target).is('input[type="radio"]') || $(e.target).is('input[type="checkbox"]'))) e.preventDefault()
})
.on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
$(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
@@ -298,10 +293,10 @@ if (typeof jQuery === 'undefined') {
}(jQuery);
/* ========================================================================
* Bootstrap: carousel.js v3.3.7
* Bootstrap: carousel.js v3.3.6
* http://getbootstrap.com/javascript/#carousel
* ========================================================================
* Copyright 2011-2016 Twitter, Inc.
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
@@ -329,7 +324,7 @@ if (typeof jQuery === 'undefined') {
.on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
}
Carousel.VERSION = '3.3.7'
Carousel.VERSION = '3.3.6'
Carousel.TRANSITION_DURATION = 600
@@ -536,14 +531,13 @@ if (typeof jQuery === 'undefined') {
}(jQuery);
/* ========================================================================
* Bootstrap: collapse.js v3.3.7
* Bootstrap: collapse.js v3.3.6
* http://getbootstrap.com/javascript/#collapse
* ========================================================================
* Copyright 2011-2016 Twitter, Inc.
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
/* jshint latedef: false */
+function ($) {
'use strict';
@@ -567,7 +561,7 @@ if (typeof jQuery === 'undefined') {
if (this.options.toggle) this.toggle()
}
Collapse.VERSION = '3.3.7'
Collapse.VERSION = '3.3.6'
Collapse.TRANSITION_DURATION = 350
@@ -749,10 +743,10 @@ if (typeof jQuery === 'undefined') {
}(jQuery);
/* ========================================================================
* Bootstrap: dropdown.js v3.3.7
* Bootstrap: dropdown.js v3.3.6
* http://getbootstrap.com/javascript/#dropdowns
* ========================================================================
* Copyright 2011-2016 Twitter, Inc.
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
@@ -769,7 +763,7 @@ if (typeof jQuery === 'undefined') {
$(element).on('click.bs.dropdown', this.toggle)
}
Dropdown.VERSION = '3.3.7'
Dropdown.VERSION = '3.3.6'
function getParent($this) {
var selector = $this.attr('data-target')
@@ -915,10 +909,10 @@ if (typeof jQuery === 'undefined') {
}(jQuery);
/* ========================================================================
* Bootstrap: modal.js v3.3.7
* Bootstrap: modal.js v3.3.6
* http://getbootstrap.com/javascript/#modals
* ========================================================================
* Copyright 2011-2016 Twitter, Inc.
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
@@ -949,7 +943,7 @@ if (typeof jQuery === 'undefined') {
}
}
Modal.VERSION = '3.3.7'
Modal.VERSION = '3.3.6'
Modal.TRANSITION_DURATION = 300
Modal.BACKDROP_TRANSITION_DURATION = 150
@@ -1056,9 +1050,7 @@ if (typeof jQuery === 'undefined') {
$(document)
.off('focusin.bs.modal') // guard against infinite focus loop
.on('focusin.bs.modal', $.proxy(function (e) {
if (document !== e.target &&
this.$element[0] !== e.target &&
!this.$element.has(e.target).length) {
if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
this.$element.trigger('focus')
}
}, this))
@@ -1255,11 +1247,11 @@ if (typeof jQuery === 'undefined') {
}(jQuery);
/* ========================================================================
* Bootstrap: tooltip.js v3.3.7
* Bootstrap: tooltip.js v3.3.6
* http://getbootstrap.com/javascript/#tooltip
* Inspired by the original jQuery.tipsy by Jason Frame
* ========================================================================
* Copyright 2011-2016 Twitter, Inc.
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
@@ -1282,7 +1274,7 @@ if (typeof jQuery === 'undefined') {
this.init('tooltip', element, options)
}
Tooltip.VERSION = '3.3.7'
Tooltip.VERSION = '3.3.6'
Tooltip.TRANSITION_DURATION = 150
@@ -1573,11 +1565,9 @@ if (typeof jQuery === 'undefined') {
function complete() {
if (that.hoverState != 'in') $tip.detach()
if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary.
that.$element
.removeAttr('aria-describedby')
.trigger('hidden.bs.' + that.type)
}
that.$element
.removeAttr('aria-describedby')
.trigger('hidden.bs.' + that.type)
callback && callback()
}
@@ -1620,10 +1610,7 @@ if (typeof jQuery === 'undefined') {
// width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
}
var isSvg = window.SVGElement && el instanceof window.SVGElement
// Avoid using $.offset() on SVGs since it gives incorrect results in jQuery 3.
// See https://github.com/twbs/bootstrap/issues/20280
var elOffset = isBody ? { top: 0, left: 0 } : (isSvg ? null : $element.offset())
var elOffset = isBody ? { top: 0, left: 0 } : $element.offset()
var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
@@ -1739,7 +1726,6 @@ if (typeof jQuery === 'undefined') {
that.$tip = null
that.$arrow = null
that.$viewport = null
that.$element = null
})
}
@@ -1776,10 +1762,10 @@ if (typeof jQuery === 'undefined') {
}(jQuery);
/* ========================================================================
* Bootstrap: popover.js v3.3.7
* Bootstrap: popover.js v3.3.6
* http://getbootstrap.com/javascript/#popovers
* ========================================================================
* Copyright 2011-2016 Twitter, Inc.
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
@@ -1796,7 +1782,7 @@ if (typeof jQuery === 'undefined') {
if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
Popover.VERSION = '3.3.7'
Popover.VERSION = '3.3.6'
Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
placement: 'right',
@@ -1885,10 +1871,10 @@ if (typeof jQuery === 'undefined') {
}(jQuery);
/* ========================================================================
* Bootstrap: scrollspy.js v3.3.7
* Bootstrap: scrollspy.js v3.3.6
* http://getbootstrap.com/javascript/#scrollspy
* ========================================================================
* Copyright 2011-2016 Twitter, Inc.
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
@@ -1914,7 +1900,7 @@ if (typeof jQuery === 'undefined') {
this.process()
}
ScrollSpy.VERSION = '3.3.7'
ScrollSpy.VERSION = '3.3.6'
ScrollSpy.DEFAULTS = {
offset: 10
@@ -2058,10 +2044,10 @@ if (typeof jQuery === 'undefined') {
}(jQuery);
/* ========================================================================
* Bootstrap: tab.js v3.3.7
* Bootstrap: tab.js v3.3.6
* http://getbootstrap.com/javascript/#tabs
* ========================================================================
* Copyright 2011-2016 Twitter, Inc.
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
@@ -2078,7 +2064,7 @@ if (typeof jQuery === 'undefined') {
// jscs:enable requireDollarBeforejQueryAssignment
}
Tab.VERSION = '3.3.7'
Tab.VERSION = '3.3.6'
Tab.TRANSITION_DURATION = 150
@@ -2214,10 +2200,10 @@ if (typeof jQuery === 'undefined') {
}(jQuery);
/* ========================================================================
* Bootstrap: affix.js v3.3.7
* Bootstrap: affix.js v3.3.6
* http://getbootstrap.com/javascript/#affix
* ========================================================================
* Copyright 2011-2016 Twitter, Inc.
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
@@ -2243,7 +2229,7 @@ if (typeof jQuery === 'undefined') {
this.checkPosition()
}
Affix.VERSION = '3.3.7'
Affix.VERSION = '3.3.6'
Affix.RESET = 'affix affix-top affix-bottom'

File diff suppressed because one or more lines are too long

View File

@@ -1,678 +0,0 @@
/*!
* Datepicker for Bootstrap v1.6.4 (https://github.com/eternicode/bootstrap-datepicker)
*
* Copyright 2012 Stefan Petre
* Improvements by Andrew Rowls
* Licensed under the Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/
.datepicker {
border-radius: 4px;
direction: ltr;
}
.datepicker-inline {
width: 220px;
}
.datepicker.datepicker-rtl {
direction: rtl;
}
.datepicker.datepicker-rtl table tr td span {
float: right;
}
.datepicker-dropdown {
top: 0;
left: 0;
padding: 4px;
}
.datepicker-dropdown:before {
content: '';
display: inline-block;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-bottom: 7px solid rgba(0, 0, 0, 0.15);
border-top: 0;
border-bottom-color: rgba(0, 0, 0, 0.2);
position: absolute;
}
.datepicker-dropdown:after {
content: '';
display: inline-block;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 6px solid #fff;
border-top: 0;
position: absolute;
}
.datepicker-dropdown.datepicker-orient-left:before {
left: 6px;
}
.datepicker-dropdown.datepicker-orient-left:after {
left: 7px;
}
.datepicker-dropdown.datepicker-orient-right:before {
right: 6px;
}
.datepicker-dropdown.datepicker-orient-right:after {
right: 7px;
}
.datepicker-dropdown.datepicker-orient-bottom:before {
top: -7px;
}
.datepicker-dropdown.datepicker-orient-bottom:after {
top: -6px;
}
.datepicker-dropdown.datepicker-orient-top:before {
bottom: -7px;
border-bottom: 0;
border-top: 7px solid rgba(0, 0, 0, 0.15);
}
.datepicker-dropdown.datepicker-orient-top:after {
bottom: -6px;
border-bottom: 0;
border-top: 6px solid #fff;
}
.datepicker table {
margin: 0;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.datepicker table tr td,
.datepicker table tr th {
text-align: center;
width: 30px;
height: 30px;
border-radius: 4px;
border: none;
}
.table-striped .datepicker table tr td,
.table-striped .datepicker table tr th {
background-color: transparent;
}
.datepicker table tr td.old,
.datepicker table tr td.new {
color: #777777;
}
.datepicker table tr td.day:hover,
.datepicker table tr td.focused {
background: #eeeeee;
cursor: pointer;
}
.datepicker table tr td.disabled,
.datepicker table tr td.disabled:hover {
background: none;
color: #777777;
cursor: default;
}
.datepicker table tr td.highlighted {
color: #000;
background-color: #d9edf7;
border-color: #85c5e5;
border-radius: 0;
}
.datepicker table tr td.highlighted:focus,
.datepicker table tr td.highlighted.focus {
color: #000;
background-color: #afd9ee;
border-color: #298fc2;
}
.datepicker table tr td.highlighted:hover {
color: #000;
background-color: #afd9ee;
border-color: #52addb;
}
.datepicker table tr td.highlighted:active,
.datepicker table tr td.highlighted.active {
color: #000;
background-color: #afd9ee;
border-color: #52addb;
}
.datepicker table tr td.highlighted:active:hover,
.datepicker table tr td.highlighted.active:hover,
.datepicker table tr td.highlighted:active:focus,
.datepicker table tr td.highlighted.active:focus,
.datepicker table tr td.highlighted:active.focus,
.datepicker table tr td.highlighted.active.focus {
color: #000;
background-color: #91cbe8;
border-color: #298fc2;
}
.datepicker table tr td.highlighted.disabled:hover,
.datepicker table tr td.highlighted[disabled]:hover,
fieldset[disabled] .datepicker table tr td.highlighted:hover,
.datepicker table tr td.highlighted.disabled:focus,
.datepicker table tr td.highlighted[disabled]:focus,
fieldset[disabled] .datepicker table tr td.highlighted:focus,
.datepicker table tr td.highlighted.disabled.focus,
.datepicker table tr td.highlighted[disabled].focus,
fieldset[disabled] .datepicker table tr td.highlighted.focus {
background-color: #d9edf7;
border-color: #85c5e5;
}
.datepicker table tr td.highlighted.focused {
background: #afd9ee;
}
.datepicker table tr td.highlighted.disabled,
.datepicker table tr td.highlighted.disabled:active {
background: #d9edf7;
color: #777777;
}
.datepicker table tr td.today {
color: #000;
background-color: #ffdb99;
border-color: #ffb733;
}
.datepicker table tr td.today:focus,
.datepicker table tr td.today.focus {
color: #000;
background-color: #ffc966;
border-color: #b37400;
}
.datepicker table tr td.today:hover {
color: #000;
background-color: #ffc966;
border-color: #f59e00;
}
.datepicker table tr td.today:active,
.datepicker table tr td.today.active {
color: #000;
background-color: #ffc966;
border-color: #f59e00;
}
.datepicker table tr td.today:active:hover,
.datepicker table tr td.today.active:hover,
.datepicker table tr td.today:active:focus,
.datepicker table tr td.today.active:focus,
.datepicker table tr td.today:active.focus,
.datepicker table tr td.today.active.focus {
color: #000;
background-color: #ffbc42;
border-color: #b37400;
}
.datepicker table tr td.today.disabled:hover,
.datepicker table tr td.today[disabled]:hover,
fieldset[disabled] .datepicker table tr td.today:hover,
.datepicker table tr td.today.disabled:focus,
.datepicker table tr td.today[disabled]:focus,
fieldset[disabled] .datepicker table tr td.today:focus,
.datepicker table tr td.today.disabled.focus,
.datepicker table tr td.today[disabled].focus,
fieldset[disabled] .datepicker table tr td.today.focus {
background-color: #ffdb99;
border-color: #ffb733;
}
.datepicker table tr td.today.focused {
background: #ffc966;
}
.datepicker table tr td.today.disabled,
.datepicker table tr td.today.disabled:active {
background: #ffdb99;
color: #777777;
}
.datepicker table tr td.range {
color: #000;
background-color: #eeeeee;
border-color: #bbbbbb;
border-radius: 0;
}
.datepicker table tr td.range:focus,
.datepicker table tr td.range.focus {
color: #000;
background-color: #d5d5d5;
border-color: #7c7c7c;
}
.datepicker table tr td.range:hover {
color: #000;
background-color: #d5d5d5;
border-color: #9d9d9d;
}
.datepicker table tr td.range:active,
.datepicker table tr td.range.active {
color: #000;
background-color: #d5d5d5;
border-color: #9d9d9d;
}
.datepicker table tr td.range:active:hover,
.datepicker table tr td.range.active:hover,
.datepicker table tr td.range:active:focus,
.datepicker table tr td.range.active:focus,
.datepicker table tr td.range:active.focus,
.datepicker table tr td.range.active.focus {
color: #000;
background-color: #c3c3c3;
border-color: #7c7c7c;
}
.datepicker table tr td.range.disabled:hover,
.datepicker table tr td.range[disabled]:hover,
fieldset[disabled] .datepicker table tr td.range:hover,
.datepicker table tr td.range.disabled:focus,
.datepicker table tr td.range[disabled]:focus,
fieldset[disabled] .datepicker table tr td.range:focus,
.datepicker table tr td.range.disabled.focus,
.datepicker table tr td.range[disabled].focus,
fieldset[disabled] .datepicker table tr td.range.focus {
background-color: #eeeeee;
border-color: #bbbbbb;
}
.datepicker table tr td.range.focused {
background: #d5d5d5;
}
.datepicker table tr td.range.disabled,
.datepicker table tr td.range.disabled:active {
background: #eeeeee;
color: #777777;
}
.datepicker table tr td.range.highlighted {
color: #000;
background-color: #e4eef3;
border-color: #9dc1d3;
}
.datepicker table tr td.range.highlighted:focus,
.datepicker table tr td.range.highlighted.focus {
color: #000;
background-color: #c1d7e3;
border-color: #4b88a6;
}
.datepicker table tr td.range.highlighted:hover {
color: #000;
background-color: #c1d7e3;
border-color: #73a6c0;
}
.datepicker table tr td.range.highlighted:active,
.datepicker table tr td.range.highlighted.active {
color: #000;
background-color: #c1d7e3;
border-color: #73a6c0;
}
.datepicker table tr td.range.highlighted:active:hover,
.datepicker table tr td.range.highlighted.active:hover,
.datepicker table tr td.range.highlighted:active:focus,
.datepicker table tr td.range.highlighted.active:focus,
.datepicker table tr td.range.highlighted:active.focus,
.datepicker table tr td.range.highlighted.active.focus {
color: #000;
background-color: #a8c8d8;
border-color: #4b88a6;
}
.datepicker table tr td.range.highlighted.disabled:hover,
.datepicker table tr td.range.highlighted[disabled]:hover,
fieldset[disabled] .datepicker table tr td.range.highlighted:hover,
.datepicker table tr td.range.highlighted.disabled:focus,
.datepicker table tr td.range.highlighted[disabled]:focus,
fieldset[disabled] .datepicker table tr td.range.highlighted:focus,
.datepicker table tr td.range.highlighted.disabled.focus,
.datepicker table tr td.range.highlighted[disabled].focus,
fieldset[disabled] .datepicker table tr td.range.highlighted.focus {
background-color: #e4eef3;
border-color: #9dc1d3;
}
.datepicker table tr td.range.highlighted.focused {
background: #c1d7e3;
}
.datepicker table tr td.range.highlighted.disabled,
.datepicker table tr td.range.highlighted.disabled:active {
background: #e4eef3;
color: #777777;
}
.datepicker table tr td.range.today {
color: #000;
background-color: #f7ca77;
border-color: #f1a417;
}
.datepicker table tr td.range.today:focus,
.datepicker table tr td.range.today.focus {
color: #000;
background-color: #f4b747;
border-color: #815608;
}
.datepicker table tr td.range.today:hover {
color: #000;
background-color: #f4b747;
border-color: #bf800c;
}
.datepicker table tr td.range.today:active,
.datepicker table tr td.range.today.active {
color: #000;
background-color: #f4b747;
border-color: #bf800c;
}
.datepicker table tr td.range.today:active:hover,
.datepicker table tr td.range.today.active:hover,
.datepicker table tr td.range.today:active:focus,
.datepicker table tr td.range.today.active:focus,
.datepicker table tr td.range.today:active.focus,
.datepicker table tr td.range.today.active.focus {
color: #000;
background-color: #f2aa25;
border-color: #815608;
}
.datepicker table tr td.range.today.disabled:hover,
.datepicker table tr td.range.today[disabled]:hover,
fieldset[disabled] .datepicker table tr td.range.today:hover,
.datepicker table tr td.range.today.disabled:focus,
.datepicker table tr td.range.today[disabled]:focus,
fieldset[disabled] .datepicker table tr td.range.today:focus,
.datepicker table tr td.range.today.disabled.focus,
.datepicker table tr td.range.today[disabled].focus,
fieldset[disabled] .datepicker table tr td.range.today.focus {
background-color: #f7ca77;
border-color: #f1a417;
}
.datepicker table tr td.range.today.disabled,
.datepicker table tr td.range.today.disabled:active {
background: #f7ca77;
color: #777777;
}
.datepicker table tr td.selected,
.datepicker table tr td.selected.highlighted {
color: #fff;
background-color: #777777;
border-color: #555555;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td.selected:focus,
.datepicker table tr td.selected.highlighted:focus,
.datepicker table tr td.selected.focus,
.datepicker table tr td.selected.highlighted.focus {
color: #fff;
background-color: #5e5e5e;
border-color: #161616;
}
.datepicker table tr td.selected:hover,
.datepicker table tr td.selected.highlighted:hover {
color: #fff;
background-color: #5e5e5e;
border-color: #373737;
}
.datepicker table tr td.selected:active,
.datepicker table tr td.selected.highlighted:active,
.datepicker table tr td.selected.active,
.datepicker table tr td.selected.highlighted.active {
color: #fff;
background-color: #5e5e5e;
border-color: #373737;
}
.datepicker table tr td.selected:active:hover,
.datepicker table tr td.selected.highlighted:active:hover,
.datepicker table tr td.selected.active:hover,
.datepicker table tr td.selected.highlighted.active:hover,
.datepicker table tr td.selected:active:focus,
.datepicker table tr td.selected.highlighted:active:focus,
.datepicker table tr td.selected.active:focus,
.datepicker table tr td.selected.highlighted.active:focus,
.datepicker table tr td.selected:active.focus,
.datepicker table tr td.selected.highlighted:active.focus,
.datepicker table tr td.selected.active.focus,
.datepicker table tr td.selected.highlighted.active.focus {
color: #fff;
background-color: #4c4c4c;
border-color: #161616;
}
.datepicker table tr td.selected.disabled:hover,
.datepicker table tr td.selected.highlighted.disabled:hover,
.datepicker table tr td.selected[disabled]:hover,
.datepicker table tr td.selected.highlighted[disabled]:hover,
fieldset[disabled] .datepicker table tr td.selected:hover,
fieldset[disabled] .datepicker table tr td.selected.highlighted:hover,
.datepicker table tr td.selected.disabled:focus,
.datepicker table tr td.selected.highlighted.disabled:focus,
.datepicker table tr td.selected[disabled]:focus,
.datepicker table tr td.selected.highlighted[disabled]:focus,
fieldset[disabled] .datepicker table tr td.selected:focus,
fieldset[disabled] .datepicker table tr td.selected.highlighted:focus,
.datepicker table tr td.selected.disabled.focus,
.datepicker table tr td.selected.highlighted.disabled.focus,
.datepicker table tr td.selected[disabled].focus,
.datepicker table tr td.selected.highlighted[disabled].focus,
fieldset[disabled] .datepicker table tr td.selected.focus,
fieldset[disabled] .datepicker table tr td.selected.highlighted.focus {
background-color: #777777;
border-color: #555555;
}
.datepicker table tr td.active,
.datepicker table tr td.active.highlighted {
color: #fff;
background-color: #337ab7;
border-color: #2e6da4;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td.active:focus,
.datepicker table tr td.active.highlighted:focus,
.datepicker table tr td.active.focus,
.datepicker table tr td.active.highlighted.focus {
color: #fff;
background-color: #286090;
border-color: #122b40;
}
.datepicker table tr td.active:hover,
.datepicker table tr td.active.highlighted:hover {
color: #fff;
background-color: #286090;
border-color: #204d74;
}
.datepicker table tr td.active:active,
.datepicker table tr td.active.highlighted:active,
.datepicker table tr td.active.active,
.datepicker table tr td.active.highlighted.active {
color: #fff;
background-color: #286090;
border-color: #204d74;
}
.datepicker table tr td.active:active:hover,
.datepicker table tr td.active.highlighted:active:hover,
.datepicker table tr td.active.active:hover,
.datepicker table tr td.active.highlighted.active:hover,
.datepicker table tr td.active:active:focus,
.datepicker table tr td.active.highlighted:active:focus,
.datepicker table tr td.active.active:focus,
.datepicker table tr td.active.highlighted.active:focus,
.datepicker table tr td.active:active.focus,
.datepicker table tr td.active.highlighted:active.focus,
.datepicker table tr td.active.active.focus,
.datepicker table tr td.active.highlighted.active.focus {
color: #fff;
background-color: #204d74;
border-color: #122b40;
}
.datepicker table tr td.active.disabled:hover,
.datepicker table tr td.active.highlighted.disabled:hover,
.datepicker table tr td.active[disabled]:hover,
.datepicker table tr td.active.highlighted[disabled]:hover,
fieldset[disabled] .datepicker table tr td.active:hover,
fieldset[disabled] .datepicker table tr td.active.highlighted:hover,
.datepicker table tr td.active.disabled:focus,
.datepicker table tr td.active.highlighted.disabled:focus,
.datepicker table tr td.active[disabled]:focus,
.datepicker table tr td.active.highlighted[disabled]:focus,
fieldset[disabled] .datepicker table tr td.active:focus,
fieldset[disabled] .datepicker table tr td.active.highlighted:focus,
.datepicker table tr td.active.disabled.focus,
.datepicker table tr td.active.highlighted.disabled.focus,
.datepicker table tr td.active[disabled].focus,
.datepicker table tr td.active.highlighted[disabled].focus,
fieldset[disabled] .datepicker table tr td.active.focus,
fieldset[disabled] .datepicker table tr td.active.highlighted.focus {
background-color: #337ab7;
border-color: #2e6da4;
}
.datepicker table tr td span {
display: block;
width: 23%;
height: 54px;
line-height: 54px;
float: left;
margin: 1%;
cursor: pointer;
border-radius: 4px;
}
.datepicker table tr td span:hover,
.datepicker table tr td span.focused {
background: #eeeeee;
}
.datepicker table tr td span.disabled,
.datepicker table tr td span.disabled:hover {
background: none;
color: #777777;
cursor: default;
}
.datepicker table tr td span.active,
.datepicker table tr td span.active:hover,
.datepicker table tr td span.active.disabled,
.datepicker table tr td span.active.disabled:hover {
color: #fff;
background-color: #337ab7;
border-color: #2e6da4;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td span.active:focus,
.datepicker table tr td span.active:hover:focus,
.datepicker table tr td span.active.disabled:focus,
.datepicker table tr td span.active.disabled:hover:focus,
.datepicker table tr td span.active.focus,
.datepicker table tr td span.active:hover.focus,
.datepicker table tr td span.active.disabled.focus,
.datepicker table tr td span.active.disabled:hover.focus {
color: #fff;
background-color: #286090;
border-color: #122b40;
}
.datepicker table tr td span.active:hover,
.datepicker table tr td span.active:hover:hover,
.datepicker table tr td span.active.disabled:hover,
.datepicker table tr td span.active.disabled:hover:hover {
color: #fff;
background-color: #286090;
border-color: #204d74;
}
.datepicker table tr td span.active:active,
.datepicker table tr td span.active:hover:active,
.datepicker table tr td span.active.disabled:active,
.datepicker table tr td span.active.disabled:hover:active,
.datepicker table tr td span.active.active,
.datepicker table tr td span.active:hover.active,
.datepicker table tr td span.active.disabled.active,
.datepicker table tr td span.active.disabled:hover.active {
color: #fff;
background-color: #286090;
border-color: #204d74;
}
.datepicker table tr td span.active:active:hover,
.datepicker table tr td span.active:hover:active:hover,
.datepicker table tr td span.active.disabled:active:hover,
.datepicker table tr td span.active.disabled:hover:active:hover,
.datepicker table tr td span.active.active:hover,
.datepicker table tr td span.active:hover.active:hover,
.datepicker table tr td span.active.disabled.active:hover,
.datepicker table tr td span.active.disabled:hover.active:hover,
.datepicker table tr td span.active:active:focus,
.datepicker table tr td span.active:hover:active:focus,
.datepicker table tr td span.active.disabled:active:focus,
.datepicker table tr td span.active.disabled:hover:active:focus,
.datepicker table tr td span.active.active:focus,
.datepicker table tr td span.active:hover.active:focus,
.datepicker table tr td span.active.disabled.active:focus,
.datepicker table tr td span.active.disabled:hover.active:focus,
.datepicker table tr td span.active:active.focus,
.datepicker table tr td span.active:hover:active.focus,
.datepicker table tr td span.active.disabled:active.focus,
.datepicker table tr td span.active.disabled:hover:active.focus,
.datepicker table tr td span.active.active.focus,
.datepicker table tr td span.active:hover.active.focus,
.datepicker table tr td span.active.disabled.active.focus,
.datepicker table tr td span.active.disabled:hover.active.focus {
color: #fff;
background-color: #204d74;
border-color: #122b40;
}
.datepicker table tr td span.active.disabled:hover,
.datepicker table tr td span.active:hover.disabled:hover,
.datepicker table tr td span.active.disabled.disabled:hover,
.datepicker table tr td span.active.disabled:hover.disabled:hover,
.datepicker table tr td span.active[disabled]:hover,
.datepicker table tr td span.active:hover[disabled]:hover,
.datepicker table tr td span.active.disabled[disabled]:hover,
.datepicker table tr td span.active.disabled:hover[disabled]:hover,
fieldset[disabled] .datepicker table tr td span.active:hover,
fieldset[disabled] .datepicker table tr td span.active:hover:hover,
fieldset[disabled] .datepicker table tr td span.active.disabled:hover,
fieldset[disabled] .datepicker table tr td span.active.disabled:hover:hover,
.datepicker table tr td span.active.disabled:focus,
.datepicker table tr td span.active:hover.disabled:focus,
.datepicker table tr td span.active.disabled.disabled:focus,
.datepicker table tr td span.active.disabled:hover.disabled:focus,
.datepicker table tr td span.active[disabled]:focus,
.datepicker table tr td span.active:hover[disabled]:focus,
.datepicker table tr td span.active.disabled[disabled]:focus,
.datepicker table tr td span.active.disabled:hover[disabled]:focus,
fieldset[disabled] .datepicker table tr td span.active:focus,
fieldset[disabled] .datepicker table tr td span.active:hover:focus,
fieldset[disabled] .datepicker table tr td span.active.disabled:focus,
fieldset[disabled] .datepicker table tr td span.active.disabled:hover:focus,
.datepicker table tr td span.active.disabled.focus,
.datepicker table tr td span.active:hover.disabled.focus,
.datepicker table tr td span.active.disabled.disabled.focus,
.datepicker table tr td span.active.disabled:hover.disabled.focus,
.datepicker table tr td span.active[disabled].focus,
.datepicker table tr td span.active:hover[disabled].focus,
.datepicker table tr td span.active.disabled[disabled].focus,
.datepicker table tr td span.active.disabled:hover[disabled].focus,
fieldset[disabled] .datepicker table tr td span.active.focus,
fieldset[disabled] .datepicker table tr td span.active:hover.focus,
fieldset[disabled] .datepicker table tr td span.active.disabled.focus,
fieldset[disabled] .datepicker table tr td span.active.disabled:hover.focus {
background-color: #337ab7;
border-color: #2e6da4;
}
.datepicker table tr td span.old,
.datepicker table tr td span.new {
color: #777777;
}
.datepicker .datepicker-switch {
width: 145px;
}
.datepicker .datepicker-switch,
.datepicker .prev,
.datepicker .next,
.datepicker tfoot tr th {
cursor: pointer;
}
.datepicker .datepicker-switch:hover,
.datepicker .prev:hover,
.datepicker .next:hover,
.datepicker tfoot tr th:hover {
background: #eeeeee;
}
.datepicker .cw {
font-size: 10px;
width: 12px;
padding: 0 2px 0 5px;
vertical-align: middle;
}
.input-group.date .input-group-addon {
cursor: pointer;
}
.input-daterange {
width: 100%;
}
.input-daterange input {
text-align: center;
}
.input-daterange input:first-child {
border-radius: 3px 0 0 3px;
}
.input-daterange input:last-child {
border-radius: 0 3px 3px 0;
}
.input-daterange .input-group-addon {
width: auto;
min-width: 16px;
padding: 4px 5px;
line-height: 1.42857143;
text-shadow: 0 1px 0 #fff;
border-width: 1px 0;
margin-left: -5px;
margin-right: -5px;
}
/*# sourceMappingURL=bootstrap-datepicker3.css.map */

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,442 @@
/*!
* Datepicker for Bootstrap
*
* Copyright 2012 Stefan Petre
* Improvements by Andrew Rowls
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
*/
.datepicker {
padding: 4px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
direction: ltr;
/*.dow {
border-top: 1px solid #ddd !important;
}*/
}
.datepicker-inline {
width: 220px;
}
.datepicker.datepicker-rtl {
direction: rtl;
}
.datepicker.datepicker-rtl table tr td span {
float: right;
}
.datepicker-dropdown {
top: 0;
left: 0;
}
.datepicker-dropdown:before {
content: '';
display: inline-block;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-bottom: 7px solid #ccc;
border-bottom-color: rgba(0, 0, 0, 0.2);
position: absolute;
top: -7px;
left: 6px;
}
.datepicker-dropdown:after {
content: '';
display: inline-block;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 6px solid #ffffff;
position: absolute;
top: -6px;
left: 7px;
}
.datepicker > div {
display: none;
}
.datepicker.days div.datepicker-days {
display: block;
}
.datepicker.months div.datepicker-months {
display: block;
}
.datepicker.years div.datepicker-years {
display: block;
}
.datepicker table {
margin: 0;
}
.datepicker td,
.datepicker th {
text-align: center;
width: 20px;
height: 20px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
border: none;
}
.table-striped .datepicker table tr td,
.table-striped .datepicker table tr th {
background-color: transparent;
}
.datepicker table tr td.day:hover {
background: #eeeeee;
cursor: pointer;
}
.datepicker table tr td.old,
.datepicker table tr td.new {
color: #999999;
}
.datepicker table tr td.disabled,
.datepicker table tr td.disabled:hover {
background: none;
color: #999999;
cursor: default;
}
.datepicker table tr td.today,
.datepicker table tr td.today:hover,
.datepicker table tr td.today.disabled,
.datepicker table tr td.today.disabled:hover {
background-color: #fde19a;
background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a);
background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a));
background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a);
background-image: -o-linear-gradient(top, #fdd49a, #fdf59a);
background-image: linear-gradient(top, #fdd49a, #fdf59a);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0);
border-color: #fdf59a #fdf59a #fbed50;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
color: #000 !important;
}
.datepicker table tr td.today:hover,
.datepicker table tr td.today:hover:hover,
.datepicker table tr td.today.disabled:hover,
.datepicker table tr td.today.disabled:hover:hover,
.datepicker table tr td.today:active,
.datepicker table tr td.today:hover:active,
.datepicker table tr td.today.disabled:active,
.datepicker table tr td.today.disabled:hover:active,
.datepicker table tr td.today.active,
.datepicker table tr td.today:hover.active,
.datepicker table tr td.today.disabled.active,
.datepicker table tr td.today.disabled:hover.active,
.datepicker table tr td.today.disabled,
.datepicker table tr td.today:hover.disabled,
.datepicker table tr td.today.disabled.disabled,
.datepicker table tr td.today.disabled:hover.disabled,
.datepicker table tr td.today[disabled],
.datepicker table tr td.today:hover[disabled],
.datepicker table tr td.today.disabled[disabled],
.datepicker table tr td.today.disabled:hover[disabled] {
background-color: #fdf59a;
}
.datepicker table tr td.today:active,
.datepicker table tr td.today:hover:active,
.datepicker table tr td.today.disabled:active,
.datepicker table tr td.today.disabled:hover:active,
.datepicker table tr td.today.active,
.datepicker table tr td.today:hover.active,
.datepicker table tr td.today.disabled.active,
.datepicker table tr td.today.disabled:hover.active {
background-color: #fbf069 \9;
}
.datepicker table tr td.range,
.datepicker table tr td.range:hover,
.datepicker table tr td.range.disabled,
.datepicker table tr td.range.disabled:hover {
background: #eeeeee;
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
}
.datepicker table tr td.range.today,
.datepicker table tr td.range.today:hover,
.datepicker table tr td.range.today.disabled,
.datepicker table tr td.range.today.disabled:hover {
background-color: #f3d17a;
background-image: -moz-linear-gradient(top, #f3c17a, #f3e97a);
background-image: -ms-linear-gradient(top, #f3c17a, #f3e97a);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f3c17a), to(#f3e97a));
background-image: -webkit-linear-gradient(top, #f3c17a, #f3e97a);
background-image: -o-linear-gradient(top, #f3c17a, #f3e97a);
background-image: linear-gradient(top, #f3c17a, #f3e97a);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3c17a', endColorstr='#f3e97a', GradientType=0);
border-color: #f3e97a #f3e97a #edde34;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
}
.datepicker table tr td.range.today:hover,
.datepicker table tr td.range.today:hover:hover,
.datepicker table tr td.range.today.disabled:hover,
.datepicker table tr td.range.today.disabled:hover:hover,
.datepicker table tr td.range.today:active,
.datepicker table tr td.range.today:hover:active,
.datepicker table tr td.range.today.disabled:active,
.datepicker table tr td.range.today.disabled:hover:active,
.datepicker table tr td.range.today.active,
.datepicker table tr td.range.today:hover.active,
.datepicker table tr td.range.today.disabled.active,
.datepicker table tr td.range.today.disabled:hover.active,
.datepicker table tr td.range.today.disabled,
.datepicker table tr td.range.today:hover.disabled,
.datepicker table tr td.range.today.disabled.disabled,
.datepicker table tr td.range.today.disabled:hover.disabled,
.datepicker table tr td.range.today[disabled],
.datepicker table tr td.range.today:hover[disabled],
.datepicker table tr td.range.today.disabled[disabled],
.datepicker table tr td.range.today.disabled:hover[disabled] {
background-color: #f3e97a;
}
.datepicker table tr td.range.today:active,
.datepicker table tr td.range.today:hover:active,
.datepicker table tr td.range.today.disabled:active,
.datepicker table tr td.range.today.disabled:hover:active,
.datepicker table tr td.range.today.active,
.datepicker table tr td.range.today:hover.active,
.datepicker table tr td.range.today.disabled.active,
.datepicker table tr td.range.today.disabled:hover.active {
background-color: #efe24b \9;
}
.datepicker table tr td.selected,
.datepicker table tr td.selected:hover,
.datepicker table tr td.selected.disabled,
.datepicker table tr td.selected.disabled:hover {
background-color: #9e9e9e;
background-image: -moz-linear-gradient(top, #b3b3b3, #808080);
background-image: -ms-linear-gradient(top, #b3b3b3, #808080);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b3b3b3), to(#808080));
background-image: -webkit-linear-gradient(top, #b3b3b3, #808080);
background-image: -o-linear-gradient(top, #b3b3b3, #808080);
background-image: linear-gradient(top, #b3b3b3, #808080);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3b3b3', endColorstr='#808080', GradientType=0);
border-color: #808080 #808080 #595959;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td.selected:hover,
.datepicker table tr td.selected:hover:hover,
.datepicker table tr td.selected.disabled:hover,
.datepicker table tr td.selected.disabled:hover:hover,
.datepicker table tr td.selected:active,
.datepicker table tr td.selected:hover:active,
.datepicker table tr td.selected.disabled:active,
.datepicker table tr td.selected.disabled:hover:active,
.datepicker table tr td.selected.active,
.datepicker table tr td.selected:hover.active,
.datepicker table tr td.selected.disabled.active,
.datepicker table tr td.selected.disabled:hover.active,
.datepicker table tr td.selected.disabled,
.datepicker table tr td.selected:hover.disabled,
.datepicker table tr td.selected.disabled.disabled,
.datepicker table tr td.selected.disabled:hover.disabled,
.datepicker table tr td.selected[disabled],
.datepicker table tr td.selected:hover[disabled],
.datepicker table tr td.selected.disabled[disabled],
.datepicker table tr td.selected.disabled:hover[disabled] {
background-color: #808080;
}
.datepicker table tr td.selected:active,
.datepicker table tr td.selected:hover:active,
.datepicker table tr td.selected.disabled:active,
.datepicker table tr td.selected.disabled:hover:active,
.datepicker table tr td.selected.active,
.datepicker table tr td.selected:hover.active,
.datepicker table tr td.selected.disabled.active,
.datepicker table tr td.selected.disabled:hover.active {
background-color: #666666 \9;
}
.datepicker table tr td.active,
.datepicker table tr td.active:hover,
.datepicker table tr td.active.disabled,
.datepicker table tr td.active.disabled:hover {
background-color: #006dcc;
background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
background-image: -o-linear-gradient(top, #0088cc, #0044cc);
background-image: linear-gradient(top, #0088cc, #0044cc);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
border-color: #0044cc #0044cc #002a80;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td.active:hover,
.datepicker table tr td.active:hover:hover,
.datepicker table tr td.active.disabled:hover,
.datepicker table tr td.active.disabled:hover:hover,
.datepicker table tr td.active:active,
.datepicker table tr td.active:hover:active,
.datepicker table tr td.active.disabled:active,
.datepicker table tr td.active.disabled:hover:active,
.datepicker table tr td.active.active,
.datepicker table tr td.active:hover.active,
.datepicker table tr td.active.disabled.active,
.datepicker table tr td.active.disabled:hover.active,
.datepicker table tr td.active.disabled,
.datepicker table tr td.active:hover.disabled,
.datepicker table tr td.active.disabled.disabled,
.datepicker table tr td.active.disabled:hover.disabled,
.datepicker table tr td.active[disabled],
.datepicker table tr td.active:hover[disabled],
.datepicker table tr td.active.disabled[disabled],
.datepicker table tr td.active.disabled:hover[disabled] {
background-color: #0044cc;
}
.datepicker table tr td.active:active,
.datepicker table tr td.active:hover:active,
.datepicker table tr td.active.disabled:active,
.datepicker table tr td.active.disabled:hover:active,
.datepicker table tr td.active.active,
.datepicker table tr td.active:hover.active,
.datepicker table tr td.active.disabled.active,
.datepicker table tr td.active.disabled:hover.active {
background-color: #003399 \9;
}
.datepicker table tr td span {
display: block;
width: 23%;
height: 54px;
line-height: 54px;
float: left;
margin: 1%;
cursor: pointer;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.datepicker table tr td span:hover {
background: #eeeeee;
}
.datepicker table tr td span.disabled,
.datepicker table tr td span.disabled:hover {
background: none;
color: #999999;
cursor: default;
}
.datepicker table tr td span.active,
.datepicker table tr td span.active:hover,
.datepicker table tr td span.active.disabled,
.datepicker table tr td span.active.disabled:hover {
background-color: #006dcc;
background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
background-image: -o-linear-gradient(top, #0088cc, #0044cc);
background-image: linear-gradient(top, #0088cc, #0044cc);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
border-color: #0044cc #0044cc #002a80;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td span.active:hover,
.datepicker table tr td span.active:hover:hover,
.datepicker table tr td span.active.disabled:hover,
.datepicker table tr td span.active.disabled:hover:hover,
.datepicker table tr td span.active:active,
.datepicker table tr td span.active:hover:active,
.datepicker table tr td span.active.disabled:active,
.datepicker table tr td span.active.disabled:hover:active,
.datepicker table tr td span.active.active,
.datepicker table tr td span.active:hover.active,
.datepicker table tr td span.active.disabled.active,
.datepicker table tr td span.active.disabled:hover.active,
.datepicker table tr td span.active.disabled,
.datepicker table tr td span.active:hover.disabled,
.datepicker table tr td span.active.disabled.disabled,
.datepicker table tr td span.active.disabled:hover.disabled,
.datepicker table tr td span.active[disabled],
.datepicker table tr td span.active:hover[disabled],
.datepicker table tr td span.active.disabled[disabled],
.datepicker table tr td span.active.disabled:hover[disabled] {
background-color: #0044cc;
}
.datepicker table tr td span.active:active,
.datepicker table tr td span.active:hover:active,
.datepicker table tr td span.active.disabled:active,
.datepicker table tr td span.active.disabled:hover:active,
.datepicker table tr td span.active.active,
.datepicker table tr td span.active:hover.active,
.datepicker table tr td span.active.disabled.active,
.datepicker table tr td span.active.disabled:hover.active {
background-color: #003399 \9;
}
.datepicker table tr td span.old {
color: #999999;
}
.datepicker th.datepicker-switch {
width: 145px;
}
.datepicker thead tr:first-child th,
.datepicker tfoot tr:first-child th {
cursor: pointer;
}
.datepicker thead tr:first-child th:hover,
.datepicker tfoot tr:first-child th:hover {
background: #eeeeee;
}
.datepicker .cw {
font-size: 10px;
width: 12px;
padding: 0 2px 0 5px;
vertical-align: middle;
}
.datepicker thead tr:first-child th.cw {
cursor: default;
background-color: transparent;
}
.input-append.date .add-on i,
.input-prepend.date .add-on i {
display: block;
cursor: pointer;
width: 16px;
height: 16px;
}
.input-daterange input {
text-align: center;
}
.input-daterange input:first-child {
-webkit-border-radius: 3px 0 0 3px;
-moz-border-radius: 3px 0 0 3px;
border-radius: 3px 0 0 3px;
}
.input-daterange input:last-child {
-webkit-border-radius: 0 3px 3px 0;
-moz-border-radius: 0 3px 3px 0;
border-radius: 0 3px 3px 0;
}
.input-daterange .add-on {
display: inline-block;
width: auto;
min-width: 16px;
height: 18px;
padding: 4px 5px;
font-weight: normal;
line-height: 18px;
text-align: center;
text-shadow: 0 1px 0 #ffffff;
vertical-align: middle;
background-color: #eeeeee;
border: 1px solid #ccc;
margin-left: -5px;
margin-right: -5px;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

@@ -0,0 +1,14 @@
/**
* Bulgarian translation for bootstrap-datepicker
* Apostol Apostolov <apostol.s.apostolov@gmail.com>
*/
;(function($){
$.fn.datepicker.dates['bg'] = {
days: ["Неделя", "Понеделник", "Вторник", "Сряда", "Четвъртък", "Петък", "Събота", "Неделя"],
daysShort: ["Нед", "Пон", "Вто", "Сря", "Чет", "Пет", "Съб", "Нед"],
daysMin: ["Н", "П", "В", "С", "Ч", "П", "С", "Н"],
months: ["Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември"],
monthsShort: ["Ян", "Фев", "Мар", "Апр", "Май", "Юни", "Юли", "Авг", "Сеп", "Окт", "Ное", "Дек"],
today: "днес"
};
}(jQuery));

View File

@@ -1 +0,0 @@
!function(a){a.fn.datepicker.dates.bg={days:["Неделя","Понеделник","Вторник","Сряда","Четвъртък","Петък","Събота"],daysShort:["Нед","Пон","Вто","Сря","Чет","Пет","Съб"],daysMin:["Н","П","В","С","Ч","П","С"],months:["Януари","Февруари","Март","Април","Май","Юни","Юли","Август","Септември","Октомври","Ноември","Декември"],monthsShort:["Ян","Фев","Мар","Апр","Май","Юни","Юли","Авг","Сеп","Окт","Ное","Дек"],today:"днес"}}(jQuery);

View File

@@ -1 +0,0 @@
!function(a){a.fn.datepicker.dates.bs={days:["Nedjelja","Ponedjeljak","Utorak","Srijeda","Četvrtak","Petak","Subota"],daysShort:["Ned","Pon","Uto","Sri","Čet","Pet","Sub"],daysMin:["N","Po","U","Sr","Č","Pe","Su"],months:["Januar","Februar","Mart","April","Maj","Juni","Juli","August","Septembar","Oktobar","Novembar","Decembar"],monthsShort:["Jan","Feb","Mar","Apr","Maj","Jun","Jul","Aug","Sep","Okt","Nov","Dec"],today:"Danas",weekStart:1,format:"dd.mm.yyyy"}}(jQuery);

View File

@@ -0,0 +1,14 @@
/**
* Catalan translation for bootstrap-datepicker
* J. Garcia <jogaco.en@gmail.com>
*/
;(function($){
$.fn.datepicker.dates['ca'] = {
days: ["Diumenge", "Dilluns", "Dimarts", "Dimecres", "Dijous", "Divendres", "Dissabte", "Diumenge"],
daysShort: ["Diu", "Dil", "Dmt", "Dmc", "Dij", "Div", "Dis", "Diu"],
daysMin: ["dg", "dl", "dt", "dc", "dj", "dv", "ds", "dg"],
months: ["Gener", "Febrer", "Març", "Abril", "Maig", "Juny", "Juliol", "Agost", "Setembre", "Octubre", "Novembre", "Desembre"],
monthsShort: ["Gen", "Feb", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Oct", "Nov", "Des"],
today: "Avui"
};
}(jQuery));

View File

@@ -1 +0,0 @@
!function(a){a.fn.datepicker.dates.ca={days:["Diumenge","Dilluns","Dimarts","Dimecres","Dijous","Divendres","Dissabte"],daysShort:["Diu","Dil","Dmt","Dmc","Dij","Div","Dis"],daysMin:["dg","dl","dt","dc","dj","dv","ds"],months:["Gener","Febrer","Març","Abril","Maig","Juny","Juliol","Agost","Setembre","Octubre","Novembre","Desembre"],monthsShort:["Gen","Feb","Mar","Abr","Mai","Jun","Jul","Ago","Set","Oct","Nov","Des"],today:"Avui",monthsTitle:"Mesos",clear:"Esborrar",weekStart:1,format:"dd/mm/yyyy"}}(jQuery);

View File

@@ -0,0 +1,15 @@
/**
* Czech translation for bootstrap-datepicker
* Matěj Koubík <matej@koubik.name>
* Fixes by Michal Remiš <michal.remis@gmail.com>
*/
;(function($){
$.fn.datepicker.dates['cs'] = {
days: ["Neděle", "Pondělí", "Úterý", "Středa", "Čtvrtek", "Pátek", "Sobota", "Neděle"],
daysShort: ["Ned", "Pon", "Úte", "Stř", "Čtv", "Pát", "Sob", "Ned"],
daysMin: ["Ne", "Po", "Út", "St", "Čt", "Pá", "So", "Ne"],
months: ["Leden", "Únor", "Březen", "Duben", "Květen", "Červen", "Červenec", "Srpen", "Září", "Říjen", "Listopad", "Prosinec"],
monthsShort: ["Led", "Úno", "Bře", "Dub", "Kvě", "Čer", "Čnc", "Srp", "Zář", "Říj", "Lis", "Pro"],
today: "Dnes"
};
}(jQuery));

View File

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

View File

@@ -1 +0,0 @@
!function(a){a.fn.datepicker.dates.cy={days:["Sul","Llun","Mawrth","Mercher","Iau","Gwener","Sadwrn"],daysShort:["Sul","Llu","Maw","Mer","Iau","Gwe","Sad"],daysMin:["Su","Ll","Ma","Me","Ia","Gwe","Sa"],months:["Ionawr","Chewfror","Mawrth","Ebrill","Mai","Mehefin","Gorfennaf","Awst","Medi","Hydref","Tachwedd","Rhagfyr"],monthsShort:["Ion","Chw","Maw","Ebr","Mai","Meh","Gor","Aws","Med","Hyd","Tach","Rha"],today:"Heddiw"}}(jQuery);

View File

@@ -0,0 +1,14 @@
/**
* Danish translation for bootstrap-datepicker
* Christian Pedersen <http://github.com/chripede>
*/
;(function($){
$.fn.datepicker.dates['da'] = {
days: ["Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag", "Søndag"],
daysShort: ["Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør", "Søn"],
daysMin: ["Sø", "Ma", "Ti", "On", "To", "Fr", "Lø", "Sø"],
months: ["Januar", "Februar", "Marts", "April", "Maj", "Juni", "Juli", "August", "September", "Oktober", "November", "December"],
monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"],
today: "I Dag"
};
}(jQuery));

View File

@@ -1 +0,0 @@
!function(a){a.fn.datepicker.dates.da={days:["søndag","mandag","tirsdag","onsdag","torsdag","fredag","lørdag"],daysShort:["søn","man","tir","ons","tor","fre","lør"],daysMin:["sø","ma","ti","on","to","fr","lø"],months:["januar","februar","marts","april","maj","juni","juli","august","september","oktober","november","december"],monthsShort:["jan","feb","mar","apr","maj","jun","jul","aug","sep","okt","nov","dec"],today:"I Dag",clear:"Nulstil"}}(jQuery);

View File

@@ -0,0 +1,16 @@
/**
* German translation for bootstrap-datepicker
* Sam Zurcher <sam@orelias.ch>
*/
;(function($){
$.fn.datepicker.dates['de'] = {
days: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"],
daysShort: ["Son", "Mon", "Die", "Mit", "Don", "Fre", "Sam", "Son"],
daysMin: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"],
months: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"],
monthsShort: ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"],
today: "Heute",
weekStart: 1,
format: "dd.mm.yyyy"
};
}(jQuery));

View File

@@ -1 +0,0 @@
!function(a){a.fn.datepicker.dates.de={days:["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"],daysShort:["Son","Mon","Die","Mit","Don","Fre","Sam"],daysMin:["So","Mo","Di","Mi","Do","Fr","Sa"],months:["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"],monthsShort:["Jan","Feb","Mär","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez"],today:"Heute",monthsTitle:"Monate",clear:"Löschen",weekStart:1,format:"dd.mm.yyyy"}}(jQuery);

View File

@@ -0,0 +1,13 @@
/**
* Greek translation for bootstrap-datepicker
*/
;(function($){
$.fn.datepicker.dates['el'] = {
days: ["Κυριακή", "Δευτέρα", "Τρίτη", "Τετάρτη", "Πέμπτη", "Παρασκευή", "Σάββατο", "Κυριακή"],
daysShort: ["Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ", "Κυρ"],
daysMin: ["Κυ", "Δε", "Τρ", "Τε", "Πε", "Πα", "Σα", "Κυ"],
months: ["Ιανουάριος", "Φεβρουάριος", "Μάρτιος", "Απρίλιος", "Μάιος", "Ιούνιος", "Ιούλιος", "Αύγουστος", "Σεπτέμβριος", "Οκτώβριος", "Νοέμβριος", "Δεκέμβριος"],
monthsShort: ["Ιαν", "Φεβ", "Μαρ", "Απρ", "Μάι", "Ιουν", "Ιουλ", "Αυγ", "Σεπ", "Οκτ", "Νοε", "Δεκ"],
today: "Σήμερα"
};
}(jQuery));

View File

@@ -1 +0,0 @@
!function(a){a.fn.datepicker.dates.el={days:["Κυριακή","Δευτέρα","Τρίτη","Τετάρτη","Πέμπτη","Παρασκευή","Σάββατο"],daysShort:["Κυρ","Δευ","Τρι","Τετ","Πεμ","Παρ","Σαβ"],daysMin:["Κυ","Δε","Τρ","Τε","Πε","Πα","Σα"],months:["Ιανουάριος","Φεβρουάριος","Μάρτιος","Απρίλιος","Μάιος","Ιούνιος","Ιούλιος","Αύγουστος","Σεπτέμβριος","Οκτώβριος","Νοέμβριος","Δεκέμβριος"],monthsShort:["Ιαν","Φεβ","Μαρ","Απρ","Μάι","Ιουν","Ιουλ","Αυγ","Σεπ","Οκτ","Νοε","Δεκ"],today:"Σήμερα",clear:"Καθαρισμός",weekStart:1,format:"d/m/yyyy"}}(jQuery);

View File

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

View File

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

View File

@@ -1 +0,0 @@
!function(a){a.fn.datepicker.dates.eo={days:["dimanĉo","lundo","mardo","merkredo","ĵaŭdo","vendredo","sabato"],daysShort:["dim.","lun.","mar.","mer.","ĵaŭ.","ven.","sam."],daysMin:["d","l","ma","me","ĵ","v","s"],months:["januaro","februaro","marto","aprilo","majo","junio","julio","aŭgusto","septembro","oktobro","novembro","decembro"],monthsShort:["jan.","feb.","mar.","apr.","majo","jun.","jul.","aŭg.","sep.","okt.","nov.","dec."],today:"Hodiaŭ",clear:"Nuligi",weekStart:1,format:"yyyy-mm-dd"}}(jQuery);

View File

@@ -0,0 +1,14 @@
/**
* Spanish translation for bootstrap-datepicker
* Bruno Bonamin <bruno.bonamin@gmail.com>
*/
;(function($){
$.fn.datepicker.dates['es'] = {
days: ["Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado", "Domingo"],
daysShort: ["Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb", "Dom"],
daysMin: ["Do", "Lu", "Ma", "Mi", "Ju", "Vi", "Sa", "Do"],
months: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"],
monthsShort: ["Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"],
today: "Hoy"
};
}(jQuery));

View File

@@ -1 +0,0 @@
!function(a){a.fn.datepicker.dates.es={days:["Domingo","Lunes","Martes","Miércoles","Jueves","Viernes","Sábado"],daysShort:["Dom","Lun","Mar","Mié","Jue","Vie","Sáb"],daysMin:["Do","Lu","Ma","Mi","Ju","Vi","Sa"],months:["Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre"],monthsShort:["Ene","Feb","Mar","Abr","May","Jun","Jul","Ago","Sep","Oct","Nov","Dic"],today:"Hoy",monthsTitle:"Meses",clear:"Borrar",weekStart:1,format:"dd/mm/yyyy"}}(jQuery);

View File

@@ -1 +0,0 @@
!function(a){a.fn.datepicker.dates.et={days:["Pühapäev","Esmaspäev","Teisipäev","Kolmapäev","Neljapäev","Reede","Laupäev"],daysShort:["Pühap","Esmasp","Teisip","Kolmap","Neljap","Reede","Laup"],daysMin:["P","E","T","K","N","R","L"],months:["Jaanuar","Veebruar","Märts","Aprill","Mai","Juuni","Juuli","August","September","Oktoober","November","Detsember"],monthsShort:["Jaan","Veebr","Märts","Apr","Mai","Juuni","Juuli","Aug","Sept","Okt","Nov","Dets"],today:"Täna",clear:"Tühjenda",weekStart:1,format:"dd.mm.yyyy"}}(jQuery);

View File

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

View File

@@ -1 +0,0 @@
!function(a){a.fn.datepicker.dates.fa={days:["یک‌شنبه","دوشنبه","سه‌شنبه","چهارشنبه","پنج‌شنبه","جمعه","شنبه","یک‌شنبه"],daysShort:["یک","دو","سه","چهار","پنج","جمعه","شنبه","یک"],daysMin:["ی","د","س","چ","پ","ج","ش","ی"],months:["ژانویه","فوریه","مارس","آوریل","مه","ژوئن","ژوئیه","اوت","سپتامبر","اکتبر","نوامبر","دسامبر"],monthsShort:["ژان","فور","مار","آور","مه","ژون","ژوی","اوت","سپت","اکت","نوا","دسا"],today:"امروز",clear:"پاک کن",weekStart:1,format:"yyyy/mm/dd"}}(jQuery);

View File

@@ -0,0 +1,14 @@
/**
* Finnish translation for bootstrap-datepicker
* Jaakko Salonen <https://github.com/jsalonen>
*/
;(function($){
$.fn.datepicker.dates['fi'] = {
days: ["sunnuntai", "maanantai", "tiistai", "keskiviikko", "torstai", "perjantai", "lauantai", "sunnuntai"],
daysShort: ["sun", "maa", "tii", "kes", "tor", "per", "lau", "sun"],
daysMin: ["su", "ma", "ti", "ke", "to", "pe", "la", "su"],
months: ["tammikuu", "helmikuu", "maaliskuu", "huhtikuu", "toukokuu", "kesäkuu", "heinäkuu", "elokuu", "syyskuu", "lokakuu", "marraskuu", "joulukuu"],
monthsShort: ["tam", "hel", "maa", "huh", "tou", "kes", "hei", "elo", "syy", "lok", "mar", "jou"],
today: "tänään"
};
}(jQuery));

View File

@@ -1 +0,0 @@
!function(a){a.fn.datepicker.dates.fi={days:["sunnuntai","maanantai","tiistai","keskiviikko","torstai","perjantai","lauantai"],daysShort:["sun","maa","tii","kes","tor","per","lau"],daysMin:["su","ma","ti","ke","to","pe","la"],months:["tammikuu","helmikuu","maaliskuu","huhtikuu","toukokuu","kesäkuu","heinäkuu","elokuu","syyskuu","lokakuu","marraskuu","joulukuu"],monthsShort:["tam","hel","maa","huh","tou","kes","hei","elo","syy","lok","mar","jou"],today:"tänään",clear:"Tyhjennä",weekStart:1,format:"d.m.yyyy"}}(jQuery);

View File

@@ -1 +0,0 @@
!function(a){a.fn.datepicker.dates.fo={days:["Sunnudagur","Mánadagur","Týsdagur","Mikudagur","Hósdagur","Fríggjadagur","Leygardagur"],daysShort:["Sun","Mán","Týs","Mik","Hós","Frí","Ley"],daysMin:["Su","Má","Tý","Mi","Hó","Fr","Le"],months:["Januar","Februar","Marts","Apríl","Mei","Juni","Juli","August","Septembur","Oktobur","Novembur","Desembur"],monthsShort:["Jan","Feb","Mar","Apr","Mei","Jun","Jul","Aug","Sep","Okt","Nov","Des"],today:"Í Dag",clear:"Reinsa"}}(jQuery);

View File

@@ -1 +0,0 @@
!function(a){a.fn.datepicker.dates.fr={days:["Dimanche","Lundi","Mardi","Mercredi","Jeudi","Vendredi","Samedi"],daysShort:["Dim","Lun","Mar","Mer","Jeu","Ven","Sam"],daysMin:["D","L","Ma","Me","J","V","S"],months:["Janvier","Février","Mars","Avril","Mai","Juin","Juillet","Août","Septembre","Octobre","Novembre","Décembre"],monthsShort:["Jan","Fév","Mar","Avr","Mai","Jui","Jul","Aou","Sep","Oct","Nov","Déc"],today:"Aujourd'hui",monthsTitle:"Mois",clear:"Effacer",weekStart:1,format:"dd.mm.yyyy"}}(jQuery);

View File

@@ -0,0 +1,16 @@
/**
* French translation for bootstrap-datepicker
* Nico Mollet <nico.mollet@gmail.com>
*/
;(function($){
$.fn.datepicker.dates['fr'] = {
days: ["Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche"],
daysShort: ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"],
daysMin: ["D", "L", "Ma", "Me", "J", "V", "S", "D"],
months: ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"],
monthsShort: ["Jan", "Fev", "Mar", "Avr", "Mai", "Jui", "Jul", "Aou", "Sep", "Oct", "Nov", "Dec"],
today: "Aujourd'hui",
weekStart: 1,
format: "dd/mm/yyyy"
};
}(jQuery));

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