diff --git a/.Rbuildignore b/.Rbuildignore
index db69196..cb1ce54 100644
--- a/.Rbuildignore
+++ b/.Rbuildignore
@@ -1,4 +1,5 @@
^.*\.Rproj$
^\.Rproj\.user$
-README.html
+man-roxygen
+inst\tests
README.md
diff --git a/.gitignore b/.gitignore
index 2562982..904c456 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
.Rproj.user
.Rhistory
.RData
-README.html
\ No newline at end of file
+README.html
+docs/Alerts2.html
\ No newline at end of file
diff --git a/DESCRIPTION b/DESCRIPTION
index 3a826ea..5d8df8a 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,13 +1,14 @@
Package: shinyBS
Type: Package
-Title: Twitter Bootstrap Components for Shiny
-Version: 0.25
-Date: 2014-03-13
+Title: Extra Twitter Bootstrap Components for Shiny
+Version: 0.62
+Date: 2015-03-31
Author: Eric Bailey
-Maintainer: Eric Bailey
-Description: Adds more Twitter Bootstrap components to the shiny interface
-Depends: methods
-Imports: shiny (>= 0.8.0)
-URL: https://github.com/ebailey78/shinyBS
+Maintainer: Eric Bailey
+Description: Adds easy access to additional Twitter Bootstrap components to Shiny.
+Imports:
+ shiny (>= 0.13.2),
+ htmltools
+URL: https://ebailey78.github.io/shinyBS
BugReports: https://github.com/ebailey78/shinyBS/issues
-License: GPL-3
+License: GPL-3
\ No newline at end of file
diff --git a/NAMESPACE b/NAMESPACE
index c0aaf43..f3c7843 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -1,47 +1,23 @@
-export(bsAlert,
-createAlert,
-closeAlert,
-bsDemo,
-bsNavDemo,
-bsGlyph,
-bsNavBar,
-updateNavBar,
-bsNavLink,
-bsNavToggleLink,
-updateToggleLink,
-pageWithNavBar,
-bsNavDivider,
-bsNavButton,
-bsNavTextInput,
-bsNavDateInput,
-bsNavDateRangeInput,
-bsNavDropDown,
-updateDropDown,
-bsNavTextOutput,
-bsPopover,
-addPopover,
-bsProgressBar,
-updateProgressBar,
-bsTooltip,
-addTooltip,
-bsTypeAhead,
-bsNavTypeAhead,
-updateTypeAhead,
-removeTooltip,
-removePopover,
-bsCollapse,
-bsCollapsePanel,
-updateCollapse,
-bsButtonGroup,
-bsButton,
-bsActionButton,
-bsToggleButton,
-updateButtonGroup,
-updateButton,
-highlightCells,
-highlightRows,
-bsMedia,
-bsModal,
-toggleModal)
-import(shiny,
- methods)
+# Generated by roxygen2 (4.1.0): do not edit by hand
+
+export(addPopover)
+export(addTooltip)
+export(bsAlert)
+export(bsButton)
+export(bsCollapse)
+export(bsCollapsePanel)
+export(bsExample)
+export(bsModal)
+export(bsPopover)
+export(bsTooltip)
+export(bsTypeahead)
+export(closeAlert)
+export(createAlert)
+export(popify)
+export(removePopover)
+export(removeTooltip)
+export(tipify)
+export(toggleModal)
+export(updateButton)
+export(updateCollapse)
+export(updateTypeahead)
diff --git a/NEWS b/NEWS
deleted file mode 100644
index 245212f..0000000
--- a/NEWS
+++ /dev/null
@@ -1,52 +0,0 @@
-Version 0.20
---------------------------------------------------------------------------------
-* pageWithNavBar()
- * I forgot to include the pageWithNavbar function in the NAMESPACE file so it
- wasn't exported
-
-* Buttons/Button Groups
- * singletons for including shinyBS's javascript and CSS files weren't added
- when only button functions were included in an app
- * buttons now have 'block' argument to create block-level buttons
- * bsButtonGroup has 'block' argument to create block-level button groups
- * Button Groups can now be vertically oriented with 'vertical' argument
-
-* Tooltips/Popovers
- * Tooltips and Popovers will now work with the new selectize-type
- selectInput's in shiny 0.9.0
-
-* Tables
- * highlightCells lets you highlight table cells based on their content
- * highlightRows lets you highlight table rows based on the content of a table
- column
-
-
-Version 0.10 (Initial Release)
---------------------------------------------------------------------------------
-* Alerts - Create alert anchors in your `ui.R` script and add alerts from
- `server.R`
-
-* Tooltips - Add and configure tooltips on any element with an `inputId` or
- `outputId` with `bsTooltip()` from the ui or with `addToolTip()` from the
- server.
-
-* Popovers - Works the same as Tooltips but useful for more content heavy
- applications.
-
-* TypeAhead - Works just like a 'textInput' but you can provide custom
- autocomplete lists to guide the user to specific inputs.
-
-* Progress Bars - Fully configurable Progress bars that can be updated and
- changed from `server.R`.
-
-* Navigation Bars - Create Bootstrap style navigation bars with buttons, links,
- dropdowns, etc that control your shiny app.
-
-* Collapse Panels - Create collapsable panels that allow you to remove some
- clutter from your app.
-
-* Buttons Groups - Create button groups that behave like radio buttons or
- checkbox groups
-
-* Buttons - Access Twitter Bootstrap styles and sizes for action buttons and
- toggle buttons
\ No newline at end of file
diff --git a/R/Alerts.R b/R/Alerts.R
new file mode 100644
index 0000000..95e3407
--- /dev/null
+++ b/R/Alerts.R
@@ -0,0 +1,82 @@
+#'Alerts
+#'
+#'Alerts allow you to communicate information to the user on the fly. Standard
+#'Bootstrap styling options give the user a hint at the type of information
+#'contained in the Alert.
+#'
+#'@section Components:
+#'There are three functions in the Alerts family:
+#' \describe{
+#' \item{\code{\link{bsAlert}}}{Used in the UI to create an anchor where your
+#' Alerts will be displayed.}
+#' \item{\code{\link{createAlert}}}{Used in the Server logic to create
+#' alerts. This would be used within a reactive context to display error
+#' or success messages to the user based on the status of that context.}
+#' \item{\code{\link{closeAlert}}}{Used in the Server logic to close an alert
+#' that is already open. By default, Alerts are dismissable by the user,
+#' but this offers you a way to close them programmatically.}
+#' }
+#'
+#'@details
+#'To create alerts in your Shiny app you must place \code{bsAlert} in your ui.
+#'This serves as an anchor that tells shinyBS where to place the alerts created
+#'with \code{createAlert}.
+#'
+#'Use \code{createAlert} in your server script to add alerts to the anchor
+#'you created with \code{bsAlert} in your ui. You can place \code{createAlert}
+#'in observers, reactives, or outputs. A common usage may be to have logic that
+#'validates a user's inputs. If they are valid produce the requested output, if
+#'not use \code{createAlert} to give the user info about what they need to
+#'change.
+#'
+#'@section Changes:
+#'\code{style} was called \code{type} in previous versions of shinyBS.
+#'
+#'\code{anchorId} was called \code{inputId} in previous versions of shinyBS.
+#'
+#'\code{content} was called \code{message} in previous versions of shinyBS.
+#'
+#'@examples
+#'
+#'library(shiny)
+#'library(shinyBS)
+#'app = shinyApp(
+#' ui =
+#' fluidPage(
+#' sidebarLayout(
+#' sidebarPanel(textInput("num1", NULL, value = 100),
+#' "divided by", textInput("num2", NULL, value = 20),
+#' "equals", textOutput("exampleOutput")),
+#' mainPanel(
+#' bsAlert("alert")
+#' )
+#' )
+#' ),
+#' server =
+#' function(input, output, session) {
+#' output$exampleOutput <- renderText({
+#' num1 <- as.numeric(input$num1)
+#' num2 <- as.numeric(input$num2)
+#'
+#' if(is.na(num1) | is.na(num2)) {
+#' createAlert(session, "alert", "exampleAlert", title = "Oops",
+#' content = "Both inputs should be numeric.", append = FALSE)
+#' } else if(num2 == 0) {
+#' createAlert(session, "alert", "exampleAlert", title = "Oops",
+#' content = "You cannot divide by 0.", append = FALSE)
+#' } else {
+#' closeAlert(session, "exampleAlert")
+#' return(num1/num2)
+#' }
+#'
+#' })
+#' }
+#')
+#'
+#'\dontrun{
+#' runApp(app)
+#'}
+#'@templateVar item_name Alerts
+#'@templateVar family_name Alerts
+#'@template footer
+NULL
\ No newline at end of file
diff --git a/R/Buttons.R b/R/Buttons.R
new file mode 100644
index 0000000..f391998
--- /dev/null
+++ b/R/Buttons.R
@@ -0,0 +1,115 @@
+#'Buttons
+#'
+#'Twitter Bootstrap gives many options for styling buttons that aren't made
+#'available by standard Shiny. Use shinyBS to create buttons of different sizes,
+#'shapes, and colors.
+#'
+#'@section Components:
+#'There are two functions in the Buttons family:
+#' \describe{
+#' \item{\code{\link{bsButton}}}{Used in the UI to create a button. Buttons
+#' can be of the type \code{action} or \code{toggle}.}
+#' \item{\code{\link{updateButton}}}{Used in the Server logic to modify the
+#' state of a button created with \code{\link{bsButton}}}
+#' }
+#'
+#'@details
+#'Create a button in the UI with \code{\link{bsButton}}. If \code{type = "action"}
+#'the button will behave like the standard \code{\link{actionButton}} in shiny.
+#'If \code{type = "toggle"} the button will behave like a \code{\link{checkboxInput}}
+#'with an on and off state. It will return \code{TRUE} or \code{FALSE} to the Server
+#'depending on its state.
+#'
+#'You can update the style and state of a \code{\link{bsButton}} from the Server
+#'logic with \code{\link{updateButton}}. For example, a button could be set to
+#'\code{disabled = TRUE} until the user has made some other selections, then once
+#'those selections have been made, an observer on the Server could use \code{\link{updateButton}}
+#'to enable the button allowing the user to proceed. Alternatively, you could set
+#'the button to \code{style = "success"} to let them know that the button is ready
+#'to be clicked.
+#'
+#'@section Changes:
+#'\code{bsActionButton} and \code{bsToggleButton} were replaced with just
+#'\code{\link{bsButton}} with a \code{type} argument.
+#'
+#'\code{icon} was added to allow placing an icon in the button.
+#'
+#'@examples
+#'library(shiny)
+#'library(shinyBS)
+#'app = shinyApp(
+#' ui =
+#' fluidPage(
+#' sidebarLayout(
+#' sidebarPanel(
+#' sliderInput("bins",
+#' "Move the slider to see its effect on the button below:",
+#' min = 1,
+#' max = 50,
+#' value = 1),
+#' bsButton("actTwo", label = "Click me if you dare!", icon = icon("ban")),
+#' tags$p("Clicking the first button below changes the disabled state of the second button."),
+#' bsButton("togOne", label = "Toggle button disabled status",
+#' block = TRUE, type = "toggle", value = TRUE),
+#' bsButton("actOne", label = "Block Action Button", block = TRUE)
+#'
+#' ),
+#' mainPanel(
+#' textOutput("exampleText")
+#' )
+#' )
+#' ),
+#' server =
+#' function(input, output, session) {
+#' observeEvent(input$togOne, ({
+#' updateButton(session, "actOne", disabled = !input$togOne)
+#' }))
+#' observeEvent(input$bins, ({
+#'
+#' b <- input$bins
+#' disabled = NULL
+#' style = "default"
+#' icon = ""
+#'
+#' if(b < 5) {
+#' disabled = TRUE
+#' icon <- icon("ban")
+#' } else {
+#' disabled = FALSE
+#' }
+#'
+#' if(b < 15 | b > 35) {
+#' style = "danger"
+#' } else if(b < 20 | b > 30) {
+#' style = "warning"
+#' } else {
+#' style = "default"
+#' icon = icon("check")
+#' }
+#'
+#' updateButton(session, "actTwo", disabled = disabled, style = style, icon = icon)
+#'
+#' }))
+#'
+#' output$exampleText <- renderText({
+#' input$actTwo
+#' b <- isolate(input$bins)
+#' txt = ""
+#' if((b > 5 & b < 15) | b > 35) {
+#' txt = "That was dangerous."
+#' } else if((b > 5 & b < 20) | b > 30) {
+#' txt = "I warned you about that."
+#' } else if(b >= 20 & b <= 30) {
+#' txt = "You have chosen... wisely."
+#' }
+#' return(txt)
+#' })
+#' }
+#')
+#'\dontrun{
+#' runApp(app)
+#'}
+#'@templateVar item_name Buttons
+#'@templateVar family_name Buttons
+#'@template footer
+NULL
\ No newline at end of file
diff --git a/R/Collapses.R b/R/Collapses.R
new file mode 100644
index 0000000..1208b8e
--- /dev/null
+++ b/R/Collapses.R
@@ -0,0 +1,71 @@
+#'Collapses
+#'
+#' Collapse panels allow you to reduce clutter in your Shiny app by making
+#' panels of information that open and close with a user's click. Any type of
+#' content can go in a collapse panel. Standard Bootstrap styling options are
+#' available.
+#'
+#'@section Components:
+#' \describe{
+#' \item{\code{\link{bsCollapse}}}{A container for holder the individual panels created by \code{\link{bsCollapsePanel}}.}
+#' \item{\code{\link{bsCollapsePanel}}}{Creates an individual Collapse Panel that resides within a \code{\link{bsCollapse}}.}
+#' \item{\code{\link{updateCollapse}}}{Used within your server logic to open/close collapse panels or change their style.}
+#'}
+#'
+#'@details
+#'Collapses are designed to mimic \code{\link{tabsetPanel}} in their implementation.
+#'Start with \code{bsCollapse} to create a panel group, then fill it with panels
+#'using \code{bsCollapsePanel}.
+#'
+#'\code{bsCollapse} acts as an input, so you can retrieve which panels are open
+#'from the input object passed to the function in \code{\link{shinyServer}}.
+#'
+#'\code{updateCollapse} can be used within your server logic to open/close
+#'collapse panels or to change their style.
+#'
+#'@section Changes:
+#'\code{style} is a new option that wasn't available in previous versions of
+#'shinyBS.
+#'
+#'@examples
+#'library(shiny)
+#'library(shinyBS)
+#'
+#'app = shinyApp(
+#' ui =
+#' fluidPage(
+#' sidebarLayout(
+#' sidebarPanel(HTML("This button will open Panel 1 using updateCollapse."),
+#' actionButton("p1Button", "Push Me!"),
+#' selectInput("styleSelect", "Select style for Panel 1",
+#' c("default", "primary", "danger", "warning", "info", "success"))
+#' ),
+#' mainPanel(
+#' bsCollapse(id = "collapseExample", open = "Panel 2",
+#' bsCollapsePanel("Panel 1", "This is a panel with just text ",
+#' "and has the default style. You can change the style in ",
+#' "the sidebar.", style = "info"),
+#' bsCollapsePanel("Panel 2", "This panel has a generic plot. ",
+#' "and a 'success' style.", plotOutput("genericPlot"), style = "success")
+#' )
+#' )
+#' )
+#' ),
+#' server =
+#' function(input, output, session) {
+#' output$genericPlot <- renderPlot(plot(rnorm(100)))
+#' observeEvent(input$p1Button, ({
+#' updateCollapse(session, "collapseExample", open = "Panel 1")
+#' }))
+#' observeEvent(input$styleSelect, ({
+#' updateCollapse(session, "collapseExample", style = list("Panel 1" = input$styleSelect))
+#' }))
+#' }
+#')
+#'\dontrun{
+#' runApp(app)
+#'}
+#'@templateVar item_name Collapses
+#'@templateVar family_name Collapses
+#'@template footer
+NULL
diff --git a/R/Modals.R b/R/Modals.R
new file mode 100644
index 0000000..0237a28
--- /dev/null
+++ b/R/Modals.R
@@ -0,0 +1,93 @@
+#'Modals
+#'
+#'Modal windows are similar to popups but are rendered within the
+#'original window. They can contain any combination of shiny inputs, shiny
+#'outputs, and html. Possible uses include extra controls that you don't want
+#'cluttering up the main app display or help pages to explain your apps
+#'operation.
+#'
+#'@section Components:
+#'There are only two functions in the Modals family:
+#' \describe{
+#' \item{\code{\link{bsModal}}}{Used in the UI to create a modal window.}
+#' \item{\code{\link{toggleModal}}}{Used in the Server logic to open or
+#' close a modal window programmatically.}
+#' }
+#'
+#'@details
+#'Use \code{\link{bsModal}} in your UI to create a modal window. It works
+#'like \code{\link{Collapses}} or \code{\link{tabPanel}}, any non-named arguments
+#'will be passed as content for the modal.
+#'
+#'Create a button or link and assign its \code{inputId} as the \code{trigger}
+#'in \code{\link{bsModal}}.
+#'
+#'@section Changes:
+#'There is now a \code{toggle} argument in \code{\link{toggleModal}} that allows
+#'you to specify whether you want the modal to open or close.
+#'
+#'The \code{size} argument in \code{\link{bsModal}} allows you to specify the
+#'size of the modal window. Either \code{small} or \code{large}.
+#'
+#'@examples
+#'library(shiny)
+#'library(shinyBS)
+#'
+#'app = shinyApp(
+#' ui =
+#' fluidPage(
+#' sidebarLayout(
+#' sidebarPanel(
+#' sliderInput("bins",
+#' "Number of bins:",
+#' min = 1,
+#' max = 50,
+#' value = 30),
+#' actionButton("tabBut", "View Table")
+#' ),
+#'
+#' mainPanel(
+#' plotOutput("distPlot"),
+#' bsModal("modalExample", "Data Table", "tabBut", size = "large",
+#' dataTableOutput("distTable"))
+#' )
+#' )
+#' ),
+#' server =
+#' function(input, output, session) {
+#'
+#' output$distPlot <- renderPlot({
+#'
+#' x <- faithful[, 2]
+#' bins <- seq(min(x), max(x), length.out = input$bins + 1)
+#'
+#' # draw the histogram with the specified number of bins
+#' hist(x, breaks = bins, col = 'darkgray', border = 'white')
+#'
+#' })
+#'
+#' output$distTable <- renderDataTable({
+#'
+#' x <- faithful[, 2]
+#' bins <- seq(min(x), max(x), length.out = input$bins + 1)
+#'
+#' # draw the histogram with the specified number of bins
+#' tab <- hist(x, breaks = bins, plot = FALSE)
+#' tab$breaks <- sapply(seq(length(tab$breaks) - 1), function(i) {
+#' paste0(signif(tab$breaks[i], 3), "-", signif(tab$breaks[i+1], 3))
+#' })
+#' tab <- as.data.frame(do.call(cbind, tab))
+#' colnames(tab) <- c("Bins", "Counts", "Density")
+#' return(tab[, 1:3])
+#'
+#' }, options = list(pageLength=10))
+#'
+#' }
+#')
+#'\dontrun{
+#' runApp(app)
+#'}
+#'@templateVar family_name Modals
+#'@templateVar item_name Modals
+#'@template footer
+NULL
diff --git a/R/Tooltips_and_Popovers.R b/R/Tooltips_and_Popovers.R
new file mode 100644
index 0000000..bce5ccf
--- /dev/null
+++ b/R/Tooltips_and_Popovers.R
@@ -0,0 +1,166 @@
+#'Tooltips and Popovers
+#'
+#'Tooltips and Popovers allow you to add additional information about controls
+#'or outputs without cluttering up your user interface. You can add a tooltip to
+#'a button that displays on hover and better explains what the button will do, or
+#'you could add a popover to an output providing further analysis of that output.
+#'
+#'@section Components:
+#'There are eight functions in the Tooltips and Popovers family:
+#' \describe{
+#' \item{\code{\link{bsTooltip}}}{Used in the UI to add a tooltip to an element
+#' in your UI.}
+#' \item{\code{\link{bsPopover}}}{Used in the UI to add a popover to an element
+#' in your UI.}
+#' \item{\code{\link{tipify}}}{Wrap any UI element in \code{tipify} to add a
+#' tooltip to the wrapped element. Preferred for elemented created with
+#' \code{\link{renderUI}}.}
+#' \item{\code{\link{popify}}}{Wrap any UI element in \code{popify} to add a
+#' popover to the wrapped element. Preferred for elements created with
+#' \code{\link{renderUI}}.}
+#' \item{\code{\link{addTooltip}}}{Used in the Server logic to add a tooltip
+#' to an element in your UI.}
+#' \item{\code{\link{addPopover}}}{Used in the Server logic to add a popover
+#' to an element in your UI.}
+#' \item{\code{\link{removeTooltip}}}{Used in the Server logic to remove a
+#' tooltip from an element in your UI.}
+#' \item{\code{\link{removePopover}}}{Used in the Server logic to remove a
+#' popover from an element in your UI.}
+#' }
+#'
+#'@details
+#'You can create tooltips and popovers from either the UI script or within the
+#'Server logic. \code{\link{bsTooltip}} and \code{\link{bsPopover}} are used in
+#'the UI, and \code{\link{addTooltip}} and \code{\link{addPopover}} are used in
+#'the Server logic. \code{\link{tipify}} and \code{\link{popify}} can be used
+#'within the UI or from within a \code{\link{renderUI}} in the Server logic. They
+#'also have the added advantage of not requiring that the UI element have an ID
+#'attribute.
+#'
+#'@note
+#'Tooltips and Popovers cannot contain shiny inputs or outputs.
+#'
+#'There must be at least one \code{shinyBS} component in the UI of your
+#'app in order for the necessary dependencies to be loaded. Because of this,
+#'\code{\link{addTooltip}} and \code{\link{addPopover}} will not work if they
+#'are the only shinyBS components in your app.
+#'
+#'Tooltips and popovers may not work on some of the more complex shiny inputs
+#'or outputs. If you encounter a problem with tooltips or popovers not appearing
+#'please file a issue on the github page so I can fix it.
+#'
+#'@section Changes:
+#'An \code{options} argument has been added to the creation functions to allow
+#'advanced users more control over how the tooltips and popovers appear. See
+#'the \href{http://getbootstrap.com}{Twitter Bootstrap 3 documentation} for more
+#'details.
+#'
+#'@examples
+#'library(shiny)
+#'library(shinyBS)
+#'
+#'app = shinyApp(
+#' ui =
+#' fluidPage(
+#' sidebarLayout(
+#' sidebarPanel(
+#' sliderInput("bins",
+#' "Number of bins:",
+#' min = 1,
+#' max = 50,
+#' value = 30),
+#' bsTooltip("bins", "The wait times will be broken into this many equally spaced bins",
+#' "right", options = list(container = "body"))
+#' ),
+#' mainPanel(
+#' plotOutput("distPlot"),
+#' uiOutput("uiExample")
+#' )
+#' )
+#' ),
+#' server =
+#' function(input, output, session) {
+#' output$distPlot <- renderPlot({
+#'
+#' # generate bins based on input$bins from ui.R
+#' x <- faithful[, 2]
+#' bins <- seq(min(x), max(x), length.out = input$bins + 1)
+#'
+#' # draw the histogram with the specified number of bins
+#' hist(x, breaks = bins, col = 'darkgray', border = 'white')
+#'
+#' })
+#' output$uiExample <- renderUI({
+#' tags$span(
+#' popify(bsButton("pointlessButton", "Button", style = "primary", size = "large"),
+#' "A Pointless Button",
+#' "This button is pointless. It does not do anything!"),
+#' tipify(bsButton("pB2", "Button", style = "inverse", size = "extra-small"),
+#' "This button is pointless too!")
+#' )
+#' })
+#' addPopover(session, "distPlot", "Data", content = paste0("
Waiting time between ",
+#' "eruptions and the duration of the eruption for the Old Faithful geyser ",
+#' "in Yellowstone National Park, Wyoming, USA.
Azzalini, A. and ",
+#' "Bowman, A. W. (1990). A look at some data on the Old Faithful geyser. ",
+#' "Applied Statistics 39, 357-365.
"), trigger = 'click')
+#' }
+#')
+#'\dontrun{
+#' runApp(app)
+#'}
+#'@templateVar item_name Tooltips_and_Popovers
+#'@templateVar family_name Tooltips_and_Popovers
+#'@template footer
+NULL
+
+
+## These Functions are common to multiple tooltip and popover functions
+# Shared functions with really long names...
+createTooltipOrPopoverOnServer <- function(session, id, type, options) {
+
+ data <- list(action = "add", type = type, id = id, options = options)
+ session$sendCustomMessage(type = "updateTooltipOrPopover", data)
+
+}
+
+createTooltipOrPopoverOnUI <- function(id, type, options) {
+
+ options = paste0("{'", paste(names(options), options, sep = "': '", collapse = "', '"), "'}")
+
+ bsTag <- shiny::tags$script(shiny::HTML(paste0("$(document).ready(function() {setTimeout(function() {shinyBS.addTooltip('", id, "', '", type, "', ", options, ")}, 500)});")))
+
+ htmltools::attachDependencies(bsTag, shinyBSDep)
+
+}
+
+buildTooltipOrPopoverOptionsList <- function(title, placement, trigger, options, content) {
+
+ if(is.null(options)) {
+ options = list()
+ }
+
+ if(!missing(content)) {
+ content <- gsub("'", "'", content, fixed = TRUE)
+ if(is.null(options$content)) {
+ options$content = shiny::HTML(content)
+ }
+ }
+
+ if(is.null(options$placement)) {
+ options$placement = placement
+ }
+
+ if(is.null(options$trigger)) {
+ if(length(trigger) > 1) trigger = paste(trigger, collapse = " ")
+ options$trigger = trigger
+ }
+
+ if(is.null(options$title)) {
+ options$title = title
+ options$title <- gsub("'", "'", options$title, fixed = TRUE)
+ }
+
+ return(options)
+
+}
\ No newline at end of file
diff --git a/R/addPopover.R b/R/addPopover.R
new file mode 100644
index 0000000..aadf0b1
--- /dev/null
+++ b/R/addPopover.R
@@ -0,0 +1,26 @@
+#'addPopover
+#'
+#'\code{addPopover} is used within the Server logic of an app to add a popover to a Shiny
+#'input or output.
+#'
+#'@param session The session object passed to function given to shinyServer.
+#'@param id The id of the element to attach the popover to.
+#'@param title The title of the popover.
+#'@param content The main content of the popover.
+#'@param placement Where the popover should appear relative to its target
+#'(\code{top}, \code{bottom}, \code{left}, or \code{right}). Defaults to \code{bottom}.
+#'@param trigger What action should cause the popover to appear? (\code{hover},
+#'\code{focus}, \code{click}, or \code{manual}). Defaults to \code{hover}.
+#'@param options A named list of additional options to be set on the popover.
+#'
+#'@templateVar item_name addPopover
+#'@templateVar family_name Tooltips_and_Popovers
+#'@template item_details
+#'@template footer
+#'@export
+addPopover <- function(session, id, title, content, placement = "bottom", trigger = "hover", options = NULL) {
+
+ options <- buildTooltipOrPopoverOptionsList(title, placement, trigger, options, content)
+ createTooltipOrPopoverOnServer(session, id, "popover", options)
+
+}
\ No newline at end of file
diff --git a/R/addTooltip.R b/R/addTooltip.R
new file mode 100644
index 0000000..f12af41
--- /dev/null
+++ b/R/addTooltip.R
@@ -0,0 +1,25 @@
+#'addTooltip
+#'
+#'\code{addTooltip} is used within the Server logic of an app to add a tooltip to a Shiny
+#'input or output.
+#'
+#'@param session The session object passed to function given to shinyServer.
+#'@param id The id of the element to attach the tooltip to.
+#'@param title The content of the tooltip.
+#'@param placement Where the tooltip should appear relative to its target
+#'(\code{top}, \code{bottom}, \code{left}, or \code{right}). Defaults to \code{"bottom"}.
+#'@param trigger What action should cause the tooltip to appear? (\code{hover},
+#'\code{focus}, \code{click}, or \code{manual}). Defaults to \code{"hover"}.
+#'@param options A named list of additional options to be set on the tooltip.
+#'
+#'@templateVar item_name addTooltip
+#'@templateVar family_name Tooltips_and_Popovers
+#'@template item_details
+#'@template footer
+#'@export
+addTooltip <- function(session, id, title, placement = "bottom", trigger = "hover", options = NULL) {
+
+ options <- buildTooltipOrPopoverOptionsList(title, placement, trigger, options)
+ createTooltipOrPopoverOnServer(session, id, "tooltip", options)
+
+}
\ No newline at end of file
diff --git a/R/bsAlert.R b/R/bsAlert.R
index 55e64a0..7e51cd3 100644
--- a/R/bsAlert.R
+++ b/R/bsAlert.R
@@ -1,22 +1,21 @@
-# Creates an alert anchor
-bsAlert <- function(inputId) {
+#'bsAlert
+#'
+#'\code{bsAlert} creates an anchor point in your UI definition. This anchor point
+#'is where alerts created in your Server logic will be displayed.
+#'
+#'@param anchorId A unique id the identifies the anchor.
+#'
+#'@templateVar item_name bsAlert
+#'@templateVar family_name Alerts
+#'@template item_details
+#'@template footer
+#'@export
+bsAlert <- function(anchorId, inline = TRUE) {
- sbsHead(tags$div(class="tbs-alert", id = inputId, " "))
-
-}
-
-# Adds and alert to an alert anchor.
-createAlert <- function(session, inputId, alertId = NULL, title=NULL, message=NULL, type=NULL, dismiss=TRUE, block=NULL, append=TRUE) {
+ class <- "sbs-alert"
+ if(!inline) class = paste(class, "sbs-alert-hover")
- data <- dropNulls(list(id=inputId, alertId = alertId, title=title, message=message, type=type, dismiss=dismiss, block=block, append=append))
-
- session$sendCustomMessage(type="createalert", data)
+ bsTag <- shiny::tags$div(class = class, id = anchorId, " ")
+ htmltools::attachDependencies(bsTag, shinyBSDep)
}
-
-# Closes and alert
-closeAlert <- function(session, alertId) {
-
- session$sendCustomMessage(type="closealert", alertId)
-
-}
\ No newline at end of file
diff --git a/R/bsButton.R b/R/bsButton.R
new file mode 100644
index 0000000..576eea6
--- /dev/null
+++ b/R/bsButton.R
@@ -0,0 +1,56 @@
+#'bsButton
+#'
+#'\code{bsButton} is used in your UI script to create customizable action and toggle
+#'buttons.
+#'
+#'@inheritParams shiny::actionButton
+#'@param style A Bootstrap style to apply to the button. (\code{default}, \code{primary},
+#'\code{success}, \code{info}, \code{warning}, or \code{danger})
+#'@param size The size of the button (\code{extra-small}, \code{small},
+#'\code{default}, or \code{large})
+#'@param type The type of button to create. (\code{action} or \code{toggle})
+#'@param block \bold{logical} Should the button take the full width of the parent element?
+#'@param disabled \bold{logical} Should the button be disabled (un-clickable)?
+#'@param value \bold{logical} If \code{type = "toggle"}, the initial value of the button.
+#'
+#'@templateVar item_name bsButton
+#'@templateVar family_name Buttons
+#'@template item_details
+#'@template footer
+#'@export
+bsButton <- function(inputId, label, icon = NULL, ..., style = "default",
+ size = "default", type = "action", block = FALSE,
+ disabled = FALSE, value = FALSE) {
+ btn <- shiny::actionButton(inputId, label, icon, ...)
+ if(type == "toggle") {
+ btn <- removeClass(btn, "action-button")
+ btn <- addClass(btn, "sbs-toggle-button")
+ if(value == TRUE) {
+ btn <- addClass(btn, "active")
+ }
+ }
+ if(style != "default") {
+ btn <- removeClass(btn, "btn-default")
+ btn <- addClass(btn, paste0("btn-", style))
+ }
+
+ size <- switch(size,
+ "extra-small" = "btn-xs",
+ "small" = "btn-sm",
+ "large" = "btn-lg",
+ "default")
+
+ if(size != "default") {
+ btn <- addClass(btn, size)
+ }
+
+ if(block == TRUE) {
+ btn <- addClass(btn, "btn-block")
+ }
+ if(disabled) {
+ btn <- addAttribs(btn, disabled = "disabled")
+ }
+
+ htmltools::attachDependencies(btn, shinyBSDep)
+
+}
\ No newline at end of file
diff --git a/R/bsButtons.R b/R/bsButtons.R
deleted file mode 100644
index ca2973a..0000000
--- a/R/bsButtons.R
+++ /dev/null
@@ -1,145 +0,0 @@
-# Generic button - used as base for bsToggleButton and bsActionButton and as
-# contents of bsButtonGroup
-bsButton <- function(inputId, label, value, style = NULL, size = NULL, block = FALSE,
- disabled = FALSE) {
-
- btn <- tags$button(id = inputId, type = "button", class = "btn sbs-btn", label)
-
- if(disabled) btn <- addClass(btn, "disabled")
- if(block) btn <- addClass(btn, "btn-block")
-
- if(!is.null(style)) {
- inputCheck(style = style, valid = c("primary", "info", "success", "warning",
- "danger", "inverse", "link"))
- btn <- addClass(btn, paste0("btn-", tolower(style)))
- }
-
- if(!is.null(size)) {
- inputCheck(size = size, valid = c("large", "small", "mini"))
- btn <- addClass(btn, paste0("btn-", tolower(size)))
- }
-
- if(!missing(value)) btn$attribs['data-value'] <- value
-
- return(sbsHead(btn))
-
-}
-
-# Creates a Toggle button that works like a checkboxinput
-bsToggleButton <- function(inputId, label, value = FALSE, style = NULL,
- size = NULL, block = FALSE, disabled = FALSE) {
-
- btn <- bsButton(inputId, label=label, style=style, size=size, block = block, disabled=disabled)
-
- btn[[2]] <- removeClass(btn[[2]], "sbs-btn")
- btn[[2]] <- addClass(btn[[2]], "sbs-toggle-button")
-
- btn[[2]]$attribs['data-toggle'] <- "button"
-
- if(value) btn[[2]] <- addClass(btn[[2]], "active bs-active")
-
- return(btn)
-
-}
-
-# Creates an action button like the default action button but with more options
-bsActionButton <- function(inputId, label, style = NULL, size = NULL, block = FALSE,
- disabled = FALSE) {
-
- btn <- bsButton(inputId, label, style = style, size=size, block = block, disabled=disabled)
-
- btn[[2]] <- removeClass(btn[[2]], "sbs-btn")
- btn[[2]] <- addClass(btn[[2]], "sbs-action-button")
-
- return(btn)
-
-}
-
-updateButton <- function(session, id, label = NULL, value = NULL, style = NULL,
- size = NULL, block = NULL, disabled = NULL) {
-
- data <- dropNulls(list(label = label, value = value, style = style,
- size = size, block = block, disabled = disabled))
-
- session$sendInputMessage(id, data)
-
-}
-
-# Creates a button group
-bsButtonGroup <- function(inputId, ..., label, toggle = "checkbox", style, size,
- value = NULL, disabled = FALSE, block = FALSE, vertical = FALSE) {
-
- # Start the button group tag
- btngrp <- tags$div(id = inputId, class = "btn-group sbs-button-group")
- btns <- list(...)
-
- if(inputCheck(toggle = toggle, valid = c("checkbox", "radio"))) {
- btngrp$attribs['data-toggle'] <- paste0("buttons-", toggle)
- }
-
- if(block) btngrp <- addClass(btngrp, "btn-block")
- if(vertical) btngrp <- addClass(btngrp, "btn-group-vertical")
-
- if(!missing(style)) {
- if(inputCheck(style = style,
- valid = c("primary", "info", "success", "warning",
- "danger", "inverse", "link"))) {
- style = paste0("btn-", style)
- }
- }
-
- if(!missing(size)) {
- if(inputCheck(size = size, valid = c("large", "small", "mini"))) {
- size = paste0("btn-", size)
- }
- }
-
- # Loop through the buttons for the group making neccesary changes
- for(btn in btns) {
-
- btn2 <- btn[[2]]
-
- if(disabled) btn2 <- addClass(btn2, "disabled")
-
- btn2$attribs['data-toggle'] <- NULL
- btn2 <- removeClass(btn2, "action-button btn-block toggle-button active")
-
- if(btn2$attribs['data-value'] %in% value) {
- btn2 <- addClass(btn2, "active bs-active")
- }
-
- if(block) btn2$name <- "span"
-
- if(!missing(size)) {
- btn2 <- removeClass(btn2, "btn-large btn-small btn-mini")
- btn2 <- addClass(btn2, size)
- }
-
- if(!missing(style)) {
- styles <- "btn-primary btn-info btn-success btn-warning btn-danger btn-inverse btn-link"
- btn2 <- removeClass(btn2, styles)
- btn2 <- addClass(btn2, style)
- }
-
- btn[[2]] <- btn2
-
- btngrp <- tagAppendChild(btngrp, btn)
-
- }
-
- if(!missing(label)) {
- btngrp <- tagList(tags$label(label, 'for' = inputId), btngrp)
- }
-
- return(sbsHead(btngrp))
-
-}
-
-updateButtonGroup <- function(session, id, toggle = NULL, style = NULL,
- size = NULL, disabled = NULL, value = NULL) {
-
- data <- dropNulls(list(toggle = toggle, style = style, size = size,
- disabled = disabled, value = value))
- session$sendInputMessage(id, data)
-
-}
\ No newline at end of file
diff --git a/R/bsCollapse.R b/R/bsCollapse.R
index 61e4274..cb34f0b 100644
--- a/R/bsCollapse.R
+++ b/R/bsCollapse.R
@@ -1,48 +1,42 @@
+#'bsCollapse
+#'
+#'\code{bsCollapse} is used in your UI to create a collapse panel group. Use
+#'\code{\link{bsCollapsePanel}} to populate this object with panels.
+#'
+#'@param \dots \code{\link{bsCollapsePanel}} elements to include in the Collapse.
+#'@param id \bold{Optional} You can use \code{input$id} in your Server logic to
+#'determine which panels are open, and \code{\link{updateCollapse}} to open/close
+#'panels.
+#'@param multiple Can more than one panel be open at a time? Defaults to \code{FALSE}.
+#'@param open The \code{value}, (or if none was supplied, the \code{title}) of
+#'the panel(s) you want open on load.
+#'
+#'@templateVar item_name bsCollapse
+#'@templateVar family_name Collapses
+#'@template item_details
+#'@template footer
+#'@export
bsCollapse <- function(..., id = NULL, multiple = FALSE, open = NULL) {
-
- if(is.null(id)) id = paste0("accordion", sprintf("%07i", as.integer(stats::runif(1, 1, 1000000))))
+
+ if(is.null(id)) id = paste0("collapse", sprintf("%07i", as.integer(stats::runif(1, 1, 1000000))))
if(!multiple & length(open) > 1) {
open <- open[1]
}
panels <- list(...)
+
for(i in seq(length(panels))) {
- if(panels[[i]]$children[[2]]$attribs$id %in% open) {
- panels[[i]]$children[[2]]$attribs$class <- paste(panels[[i]]$children[[2]]$attribs$class, "in")
+ if(getAttribs(panels[[i]])$value %in% open) {
+ panels[[i]]$children[[2]] <- addClass(panels[[i]]$children[[2]], "in")
+ }
+ if(!multiple) {
+ panels[[i]]$children[[1]]$children[[1]]$children[[1]] <- addAttribs(panels[[i]]$children[[1]]$children[[1]]$children[[1]], 'data-parent' = paste0("#", id))
}
- }
-
- sbsHead(tags$div(class="accordion", id = id, "data-multiple" = multiple, panels))
-
-}
-
-bsCollapsePanel <- function(title, ..., id = NULL, value = NULL) {
-
- content <- list(...)
-
- if(is.null(id)) id <- paste0("cpanel", sprintf("%07i", as.integer(stats::runif(1, 1, 1000000))))
-
- if(is.null(value)) {
- value = title
}
- tags$div(class = "accordion-group",
- tags$div(class = "accordion-heading",
- tags$a(class = "accordion-toggle", 'data-toggle' = "collapse", href = paste0("#", id), title)
- ),
- tags$div(class = "accordion-body collapse", id = id, "data-value" = value,
- tags$div(class = "accordion-inner", content)
- )
- )
-
+ bsTag <- shiny::tags$div(class = "panel-group sbs-panel-group", "data-sbs-multi" = multiple, id=id, role = "tablist", panels)
+ htmltools::attachDependencies(bsTag, shinyBSDep)
}
-
-updateCollapse <- function(session, id, open = NULL, close = NULL, multiple = NULL) {
-
- data <- dropNulls(list(open = open, close = close, multiple = multiple))
- session$sendInputMessage(id, data)
-
-}
\ No newline at end of file
diff --git a/R/bsCollapsePanel.R b/R/bsCollapsePanel.R
new file mode 100644
index 0000000..5f5f16f
--- /dev/null
+++ b/R/bsCollapsePanel.R
@@ -0,0 +1,42 @@
+#'bsCollapsePanel
+#'
+#'\code{bsCollapsePanel} creates individual panels within a \code{\link{bsCollapse}} object.
+#'
+#'@param title The title to display at the top of the panel.
+#'@param \dots UI elements to include within the panel.
+#'@param value \bold{Optional} The value to return when this panel is open. Defaults to \code{title}.
+#'@param style \bold{Optional} A Bootstrap style to apply to the panel. (\code{primary}, \code{danger}, \code{warning}, \code{info}, or \code{success})
+#'
+#'@templateVar item_name bsCollapsePanel
+#'@templateVar family_name Collapses
+#'@template item_details
+#'@template footer
+#'@export
+bsCollapsePanel <- function(title, ..., value = title, style = NULL) {
+
+ content <- list(...)
+
+ id <- paste0("cpanel", sprintf("%07i", as.integer(stats::runif(1, 1, 1000000))))
+ if(is.null(value)) {
+ value = title
+ }
+ if(is.null(style)) {
+ style = "default"
+ }
+
+ bsTag <- shiny::tags$div(class = paste0("panel panel-", style), value = value,
+ shiny::tags$div(class = "panel-heading", role = "tab", id = paste0("heading_", id),
+ shiny::tags$h4(class = "panel-title",
+ shiny::tags$a("data-toggle" = "collapse", href = paste0("#", id), title)
+ )
+ ),
+ shiny::tags$div(id = id, class = "panel-collapse collapse", role = "tabpanel",
+ shiny::tags$div(class = "panel-body", content)
+ )
+ )
+
+ htmltools::attachDependencies(bsTag, shinyBSDep)
+
+}
+
+
diff --git a/R/bsDemo.R b/R/bsDemo.R
deleted file mode 100644
index 50593a3..0000000
--- a/R/bsDemo.R
+++ /dev/null
@@ -1,20 +0,0 @@
-# Open the demo app that shows all current functionality of the shinyBS package.
-bsDemo <- function(port = NULL, launch.browser = getOption("shiny.launch.browser",
- interactive())) {
-
- examplesDir <- system.file("examples", package = "shinyBS")
- dir <- normalizePath(paste(examplesDir, "demo", sep = "/"))
- runApp(dir, port = port, launch.browser = launch.browser)
-
-}
-
-bsNavDemo <- function(port = NULL, launch.browser = getOption("shiny.launch.browser",
- interactive())) {
-
- examplesDir <- system.file("examples", package = "shinyBS")
- dir <- normalizePath(paste(examplesDir, "navbar", sep = "/"))
- runApp(dir, port = port, launch.browser = launch.browser)
-
-}
-
-
\ No newline at end of file
diff --git a/R/bsExample.R b/R/bsExample.R
new file mode 100644
index 0000000..ce758a7
--- /dev/null
+++ b/R/bsExample.R
@@ -0,0 +1,41 @@
+#'bsExample
+#'
+#'A function to view examples of shinyBS functionality. Will run the examples
+#'found in the examples sections of shinyBS documentation. Use this instead of
+#'\code{example}.
+#'
+#'@param family A shinyBS family name
+#'@param display.mode The display mode to use when running the example. See
+#'\code{\link{runApp}}.
+#'@param \dots Other parameters to pass to \code{\link{runApp}}.
+#'
+#'@details
+#'This function is just a wrapper for \code{\link{runApp}} that runs copies of the
+#'examples found in the family documention pages of \code{shinyBS}. By default,
+#'\code{display.mode} is set to \code{showcase} so you can see the code while
+#'the app is running.
+#'
+#'@examples
+#'\dontrun{
+#' bsExample("Alerts")}
+#'@export
+bsExample <- function(family, display.mode = "showcase", ...) {
+
+ exp <- system.file("examples", package="shinyBS")
+ fams <- list.dirs(exp, full.names = FALSE, recursive = FALSE)
+
+ appname <- gsub(" ", "", family, fixed = TRUE)
+ appname <- gsub("_", "", appname, fixed = TRUE)
+
+ if(appname %in% fams) {
+
+ appname <- normalizePath(paste0(exp, "/", appname))
+ shiny::runApp(appname, display.mode = display.mode, ...)
+
+ } else {
+
+ stop("Could not find shinyBS family: ", family, "\nAvailable families are: ", paste0(fams, collapse = ", "))
+
+ }
+
+}
\ No newline at end of file
diff --git a/R/bsGlyph.R b/R/bsGlyph.R
deleted file mode 100644
index 6c92a85..0000000
--- a/R/bsGlyph.R
+++ /dev/null
@@ -1,6 +0,0 @@
-# Add a glyph-icon to a shiny element
-bsGlyph <- function(name, white = FALSE) {
- class <- name
- if(white) class <- paste(class, "icon-white")
- tags$i(class=class)
-}
\ No newline at end of file
diff --git a/R/bsModal.R b/R/bsModal.R
index 574c82d..38d638f 100644
--- a/R/bsModal.R
+++ b/R/bsModal.R
@@ -1,29 +1,62 @@
-bsModal <- function(id, title, trigger, ..., href) {
-
- mo <- tags$div(class = "modal sbs-modal hide fade", id = id,
- "data-trigger" = trigger,
- tags$div(class = "modal-header",
- tags$button(Type = "button", class = "close",
- "data-dismiss" = "modal", HTML("×")),
- tags$h3(title)),
- body <- tags$div(class = "modal-body"),
- tags$div(class = "modal-footer",
- tags$a(href = "#", class = "btn", "data-dismiss" = "modal", "Close")
- )
- )
-
- if(!missing(href)) {
- mo <- addAttribs(mo, "data-remote" = href)
+#'bsModal
+#'
+#'\code{bsModal} is used within the UI to create a modal window.
+#'
+#'@param id A unique identifier for the modal window
+#'@param title The title to appear at the top of the modal
+#'@param trigger The id of a button or link that will open the modal.
+#'@param \dots UI elements to include within the modal
+#'@param size \bold{Optional} What size should the modal be? (\code{small} or \code{large})
+#'@param footer A \code{list} of shiny UI elements to be added to the footer of the modal.
+#'@param close.button Should a close button be added to the footer of the modal?
+#'@param width An optional width argument for the modal. Must include units. Only applied if \code{size} is missing.
+#'@templateVar item_name bsModal
+#'@templateVar family_name Modals
+#'@template item_details
+#'@template footer
+#'@export
+bsModal <- function(id, title, trigger, ..., size, footer = NULL, close.button = TRUE, width = NULL) {
+ if(!missing(size)) {
+ if(size == "large") {
+ size = "modal-lg"
+ } else if(size == "small") {
+ size = "modal-sm"
+ }
+ size <- paste("modal-dialog", size)
+ width = NULL
} else {
- mo$children[[2]] <- tagAppendChildren(mo$children[[2]], list = list(...))
+ size <- "modal-dialog"
}
-
- return(mo)
-}
-
-toggleModal <- function(session, modalId) {
+ if(is.null(footer)) {
+ footer <- tagList()
+ }
- session$sendInputMessage(modalId, list(toggle = TRUE))
+ if(close.button) {
+ footer <- shiny::tagAppendChild(footer, tagList(shiny::tags$button(type = "button", class = "btn btn-default", "data-dismiss" = "modal", "Close")))
+ }
-}
\ No newline at end of file
+ bsTag <- shiny::tags$div(class = size,
+ shiny::tags$div(class = "modal-content",
+ shiny::tags$div(class = "modal-header",
+ shiny::tags$button(type = "button", class = "close", "data-dismiss" = "modal", shiny::tags$span(shiny::HTML("×"))),
+ shiny::tags$h4(class = "modal-title", title)
+ ),
+ shiny::tags$div(class = "modal-body", list(...)),
+ shiny::tags$div(class = "modal-footer",
+ footer
+ )
+ )
+ )
+
+ if(!is.null(width)) {
+ bsTag <- addAttribs(bsTag, style = paste0("width: ", width, " !important;"))
+ }
+
+ bsTag <- shiny::tags$div(class = "modal sbs-modal fade", id = id, tabindex = "-1", "data-sbs-trigger" = trigger,
+ bsTag
+ )
+
+ htmltools::attachDependencies(bsTag, shinyBSDep)
+
+}
diff --git a/R/bsNavBar.R b/R/bsNavBar.R
deleted file mode 100644
index cb97faa..0000000
--- a/R/bsNavBar.R
+++ /dev/null
@@ -1,38 +0,0 @@
-# Creates the shell of a navbar that can have navbar elements added to it.
-bsNavBar <- function(inputId, brand, ..., rightItems, fixed=FALSE, inverse=FALSE) {
-
- class <- "navbar"
- if(inverse) class <- paste(class, "navbar-inverse")
- if(fixed) class <- paste(class, "navbar-fixed-top")
-
- leftItems <- list(...)
- if(missing(rightItems)) rightItems = list("")
-
- sbsHead(tags$div(id = inputId, class = class,
- tags$div(class = "navbar-inner",
- tags$a(class="brand", href="#", brand),
- tags$ul(class="nav pull-left", leftItems),
- tags$ul(class="nav pull-right", rightItems)
- )
- )
- )
-
-}
-
-# Allows the user to change some aspects of th navbar from the server.
-updateNavBar <- function(session, inputId, brand=NULL, fixed=NULL, inverse=NULL) {
-
- data <- dropNulls(list(id=inputId, brand=brand, fixed=fixed, inverse=inverse))
-
- session$sendCustomMessage(type="modifynavbar", data)
-
-}
-
-# Wrapper for creating a page with a navbar
-pageWithNavBar <- function(title = "", navbar, mainContent) {
-
- basicPage(tags$head(tags$title(title)),
- navbar,
- mainContent)
-
-}
\ No newline at end of file
diff --git a/R/bsNavBarInputs.R b/R/bsNavBarInputs.R
deleted file mode 100644
index 70043c1..0000000
--- a/R/bsNavBarInputs.R
+++ /dev/null
@@ -1,116 +0,0 @@
-# Create a link input for a navbar that acts like an actionButton
-bsNavLink <- function(inputId, label, href="#") {
-
- if(!inherits(label, "shiny.tag")) label <- HTML(label)
-
- tags$li(tags$a(id = inputId, type="button", href = href, class="action-button", label))
-
-}
-
-# Create a link input for a navbar that acts like a checkboxInput
-bsNavToggleLink <- function(inputId, label, value=FALSE) {
-
- if(!inherits(label, "shiny.tag")) label <- HTML(label)
-
- class = ""
- if(value) class = "active"
-
- tags$li(class = class, tags$a(id = inputId, href="#", class = "sbs-toggle", label))
-
-}
-
-# Update a toggleLink object
-updateToggleLink <- function(session, inputId, label=NULL, value=NULL) {
- data <- dropNulls(list(label=label, value = value))
-
- session$sendInputMessage(inputId, data)
-
-}
-
-# Create a vertical divider between navbar elements
-bsNavDivider <- function() {
- tags$li(class="divider-vertical")
-}
-
-# Wraps actionbutton in a li so it works with bsNavBar
-bsNavButton <- function(inputId, label) {
-
- tags$li(tags$form(class="navbar-form", actionButton(inputId, label)))
-
-}
-
-# Same as textInput but with label and a placeholder and optional width argument to save space
-bsNavTextInput <- function(inputId, label, value = "", width=NULL) {
-
- style = ""
- if(!is.null(width)) style = paste0("width: ", width, "px;")
-
- tags$li(tags$form(class="navbar-form", tags$input(id = inputId, style=style, type = "text", value = value, placeholder=label)))
-
-}
-
-# dateInput element for navbars
-bsNavDateInput <- function(inputId, label, value = NULL, min = NULL,
- max = NULL, format = "yyyy-mm-dd", startview = "month",
- weekstart = 0, language = "en", width = NULL) {
-
- 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")
-
- style = ""
- if(!is.null(width)) style = paste0("width: ", width, "px;")
-
- tagList(singleton(tags$head(tags$script(src = "shared/datepicker/js/bootstrap-datepicker.min.js"),
- tags$link(rel = "stylesheet", type = "text/css", href = "shared/datepicker/css/datepicker.css"))),
- tags$li(tags$form(id = inputId, class = "shiny-date-input navbar-form", tags$input(type = "text", style = style, class = "input-medium datepicker", placeholder = label,
- `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)
- )
- )
- )
-}
-
-# Same as dateRangeInput with slight formatting modification. Would like to figure out how to remove space from between date inputs
-bsNavDateRangeInput <- function(inputId, label, start = NULL, end = NULL,
- min = NULL, max = NULL, format = "yyyy-mm-dd",
- startview = "month", weekstart = 0, language = "en", width=NULL) {
-
- if (inherits(start, "Date"))
- start <- format(start, "%Y-%m-%d")
- if (inherits(end, "Date"))
- end <- format(end, "%Y-%m-%d")
- if (inherits(min, "Date"))
- min <- format(min, "%Y-%m-%d")
- if (inherits(max, "Date"))
- max <- format(max, "%Y-%m-%d")
-
- style = ""
- if(!is.null(width)) style = paste0("width: ", width, "px;")
-
- x <- label # Just a placeholder
-
- tagList(singleton(tags$head(tags$script(src = "shared/datepicker/js/bootstrap-datepicker.min.js"),
- tags$link(rel = "stylesheet", type = "text/css", href = "shared/datepicker/css/datepicker.css"))),
- tags$li(tags$form(id = inputId, class = "shiny-date-range-input input-daterange navbar-form",
- tags$input(class = "input-small", style = style, placeholder="Start Date",
- type = "text", `data-date-language` = language,
- `data-date-weekstart` = weekstart, `data-date-format` = format,
- `data-date-start-view` = startview, `data-min-date` = min,
- `data-max-date` = max, `data-initial-date` = start),
- tags$input(class = "input-small", style = style, placeholder="End Date",
- type = "text", `data-date-language` = language,
- `data-date-weekstart` = weekstart, `data-date-format` = format,
- `data-date-start-view` = startview, `data-min-date` = min,
- `data-max-date` = max, `data-initial-date` = end)
- )
- )
- )
-
-
-}
-
diff --git a/R/bsNavDropDown.R b/R/bsNavDropDown.R
deleted file mode 100644
index 4dfd25b..0000000
--- a/R/bsNavDropDown.R
+++ /dev/null
@@ -1,91 +0,0 @@
-# Creates a dropdown shiny input that returns the value of the last dropdown element clicked
-
-processChoice <- function(choice) {
-
- cname <- names(choice)
- if(is.null(cname)) cname <- ""
- if(cname == "") cname = choice[[1]]
-
- if(inherits(choice[[1]], "bsmedia")) {
- ddi <- tags$li("data-value" = cname, tags$a(tabindex = "-1", href="#", choice[[1]]))
-
- } else if(!is.list(choice[[1]])) {
- if(is.na(choice[[1]])) {
- if(is.na(cname)) {
- ddi <- tags$li(class = "divider")
- } else {
- ddi <- tags$li(class = "nav-header", cname)
- }
- } else {
- ddi <- tags$li("data-value" = choice[[1]], tags$a(tabindex = "-1", href = "#", cname))
- }
- } else {
- ddi <- tags$li(class = "dropdown-submenu",
- tags$a(tabindex = "-1", href = "#", cname))
- sdd <- tags$ul(class = "dropdown-menu")
- for(i in seq(length(choice[[1]]))) {
- sdd <- tagAppendChild(sdd, processChoice(choice[[1]][i]))
- }
- ddi <- tagAppendChild(ddi, sdd)
-
- }
-
- return(ddi)
-
-}
-
-bsNavDropDown <- function(inputId, label, choices, selected="") {
-
- #If label isn't already a shiny tag make it HTML
- if(!inherits(label, "shiny.tag")) label <- HTML(label)
-
- # Start the dropdown HTML
- dd <- tags$li(id = inputId, class = "dropdown sbs-dropdown", "data-value" = selected,
- tags$a(href="#", class = "dropdown-toggle", "data-toggle" = "dropdown", label, tags$b(class = "caret")))
-
- ddm <- tags$ul(class = "dropdown-menu")
-
- for(i in seq(length(choices))) {
- ddm <- tagAppendChild(ddm, processChoice(choices[i]))
- }
-
- return(tagAppendChild(dd, ddm))
-
-}
-
-# Allows updating out navbar dropdowns.
-updateDropDown <- function(session, inputId, label=NULL, choices=NULL, selected=NULL) {
-
- if(!is.null(choices)) {
- options <- tags$ul(class = "dropdown-menu")
- for(i in seq(length(choices))) {
- options <- tagAppendChild(options, processChoice(choices[i]))
- }
- options <- as.character(options)
- } else {
- options <- NULL
- }
-
- message <- dropNulls(list(label = label, options = options,
- value = selected))
-
- session$sendInputMessage(inputId, message)
-
-}
-
-bsMedia <- function(id, heading, text, image) {
-
- med <- tags$div(class = "media", id = id)
-
- if(!missing(image)) {
- med <- tagAppendChild(med, tags$div(class = "pull-left", href = "#", tags$img(class = "media-object", src = image, "data-src" = image)))
- }
-
- med <- tagAppendChild(med, tags$div(class = "media-body",
- tags$h4(class = "media-heading", heading), text))
-
- class(med) <- c(class(med), "bsmedia")
-
- return(med)
-
-}
\ No newline at end of file
diff --git a/R/bsNavText.R b/R/bsNavText.R
deleted file mode 100644
index 1494d44..0000000
--- a/R/bsNavText.R
+++ /dev/null
@@ -1,4 +0,0 @@
-# same as textOutput but wrapped for better formatting in navbar
-bsNavTextOutput <- function(outputId) {
- tags$li(tags$p(id = outputId, class="navbar-text shiny-text-output"))
-}
diff --git a/R/bsPopover.R b/R/bsPopover.R
index ea09953..28f190a 100644
--- a/R/bsPopover.R
+++ b/R/bsPopover.R
@@ -1,24 +1,26 @@
-# Add a popover from the ui.R script
-bsPopover <- function(id, title, content, placement="right", trigger="click") {
-
- sbsHead(tags$script(HTML(paste0("$(document).ready(function() {setTimeout(function() {addPopover('", id, "', '", title, "', '", content,
- "', '", placement, "', '", trigger, "')}, 100);})"))))
+#'bsPopover
+#'
+#'\code{bsPopover} is used within the UI of an app to add a popover to a Shiny
+#'input or output.
+#'
+#'@param id The id of the element to attach the popover to.
+#'@param title The title of the popover.
+#'@param content The main content of the popover.
+#'@param placement Where the popover should appear relative to its target
+#'(\code{top}, \code{bottom}, \code{left}, or \code{right}). Defaults to \code{"bottom"}.
+#'@param trigger What action should cause the popover to appear? (\code{hover},
+#'\code{focus}, \code{click}, or \code{manual}). Defaults to \code{"hover"}.
+#'@param options A named list of additional options to be set on the popover.
+#'
+#'@templateVar item_name bsPopover
+#'@templateVar family_name Tooltips_and_Popovers
+#'@template item_details
+#'@template footer
+#'@export
+bsPopover <- function(id, title, content, placement="bottom", trigger="hover", options = NULL) {
-}
-
-# Used to dynamically create popovers in server.R
-addPopover <- function(session, id, title="", content, placement="right", trigger="click") {
-
- data <- list(id = id, title = title, content = content,
- placement = placement, trigger = trigger)
+ options = buildTooltipOrPopoverOptionsList(title, placement, trigger, options, content)
- session$sendCustomMessage(type="addpopover", data)
-
-}
-
-#Remove popover
-removePopover <- function(session, id) {
-
- session$sendCustomMessage(type="removepopover", id)
+ createTooltipOrPopoverOnUI(id, "popover", options)
}
\ No newline at end of file
diff --git a/R/bsProgressBar.R b/R/bsProgressBar.R
deleted file mode 100644
index ddceaf5..0000000
--- a/R/bsProgressBar.R
+++ /dev/null
@@ -1,33 +0,0 @@
-# Create a progressbar in ui.R
-bsProgressBar <- function(inputId, value = 0, visible=TRUE,
- color, striped=FALSE, animate=FALSE) {
-
- class = "progress"
- if(striped) {
- class=paste(class, "progress-striped")
- } else if(animate) {
- class=paste(class, "progress-striped active")
- }
- if(!missing(color)) {
- class=paste0(class, " progress-", color)
- }
- if(!visible) {
- class=paste(class, "hidden")
- }
-
- sbsHead(tags$div(class=class, id=inputId,
- tags$div(class="bar", style=paste0("width: ", value, "%;"))
- )
- )
-
-}
-
-# Update the progress bar from server.R
-updateProgressBar <- function(session, inputId, value=NULL, visible=NULL, color=NULL, striped=NULL, animate=NULL) {
-
- data <- dropNulls(list(id=inputId, value=value, visible=visible,
- color=color, striped=striped, animate=animate))
-
- session$sendCustomMessage("updateprogress", data)
-
-}
\ No newline at end of file
diff --git a/R/bsTable.R b/R/bsTable.R
deleted file mode 100644
index c9c3c14..0000000
--- a/R/bsTable.R
+++ /dev/null
@@ -1,19 +0,0 @@
-highlightCells <- function(session, id, min = NULL, max = NULL, regex = NULL, column = NULL,
- class = NULL, style = NULL, reset = NULL, skip.row.names = TRUE) {
-
- data <- dropNulls(list(id = id, min = min, max = max, regex = regex, column = column,
- class = class, style = style, reset = reset, skip = skip.row.names))
-
- session$sendCustomMessage("highlightCells", data)
-
-}
-
-highlightRows <- function(session, id, column, min=NULL, max=NULL, regex = NULL,
- class = NULL, style = NULL, reset = NULL) {
-
- data <- dropNulls(list(id = id, column = column, min = min, max = max, regex = regex,
- class = class, style = style, reset = reset))
-
- session$sendCustomMessage("highlightRows", data)
-
-}
\ No newline at end of file
diff --git a/R/bsTooltip.R b/R/bsTooltip.R
index 76268d3..ae04f6e 100644
--- a/R/bsTooltip.R
+++ b/R/bsTooltip.R
@@ -1,27 +1,25 @@
-# Used to create a tooltip from ui.R
-bsTooltip <- function(id, title, placement="bottom", trigger="hover") {
-
- if(length(trigger) > 1) trigger = paste(trigger, collapse = " ")
-
- sbsHead(tags$script(paste0("$(document).ready(function() {setTimeout(function() {addTooltip('", id, "', '", title, "', '",
- placement, "', '", trigger, "')}, 100)});")))
-
-}
-
-# Remove Tooltip from object
-removeTooltip <- function(session, id) {
-
- session$sendCustomMessage(type="removetooltip", id)
-
-}
-
-# Used to dynamically create tooltips in server.R
-addTooltip <- function(session, id, title, placement = "bottom", trigger = "hover") {
-
- if(length(trigger) > 1) trigger = paste(trigger, collapse = " ")
-
- data <- list(id = id, title = title, placement = placement, trigger = trigger)
- session$sendCustomMessage(type="addtooltip", data)
-
-}
-
+#'bsTooltip
+#'
+#'\code{bsTooltip} is used within the UI of an app to add a tooltip to a Shiny
+#'input or output.
+#'
+#'@param id The id of the element to attach the tooltip to.
+#'@param title The content of the tooltip.
+#'@param placement Where the tooltip should appear relative to its target
+#'(\code{top}, \code{bottom}, \code{left}, or \code{right}). Defaults to \code{"bottom"}.
+#'@param trigger What action should cause the tooltip to appear? (\code{hover},
+#'\code{focus}, \code{click}, or \code{manual}). Defaults to \code{"hover"}.
+#'@param options A named list of additional options to be set on the tooltip.
+#'
+#'@templateVar item_name bsTooltip
+#'@templateVar family_name Tooltips_and_Popovers
+#'@template item_details
+#'@template footer
+#'@export
+bsTooltip <- function(id, title, placement="bottom", trigger="hover", options = NULL) {
+
+ options = buildTooltipOrPopoverOptionsList(title, placement, trigger, options)
+
+ createTooltipOrPopoverOnUI(id, "tooltip", options)
+
+}
\ No newline at end of file
diff --git a/R/bsTypeAhead.R b/R/bsTypeAhead.R
deleted file mode 100644
index 1513ff3..0000000
--- a/R/bsTypeAhead.R
+++ /dev/null
@@ -1,41 +0,0 @@
-# Create a typeahead text input
-bsTypeAhead <- function(inputId, label, value = "", choices, items=8, minLength=1) {
-
- choices <- paste0("[\'", paste0(choices, collapse="\', \'") , "\']")
-
- sbsHead(tagList(tags$label(label, `for` = inputId),
- tags$input(id = inputId, type="text", class="sbs-typeahead",
- "data-provide"="typeahead", autocomplete="off",
- value = value),
- tags$script(paste0("$('#", inputId, "').typeahead({source: ", choices, ",
- items: ", items, ",
- minLength: ", minLength, "})"))
- )
- )
-
-}
-
-# Same as bsTypeAhead but with label as placeholder and optional width argument to save space.
-bsNavTypeAhead <- function(inputId, label, value = "", choices, items=8, minLength=1, width = NULL) {
-
- choices <- paste0("[\"", paste0(choices, collapse="\", \"") , "\"]")
-
- style = ""
- if(!is.null(width)) style = paste0("width: ", width, "px;")
-
-
- tags$li(tags$form(class="navbar-form", tags$input(id = inputId, type="text", class="sbs-typeahead",
- "data-provide"="typeahead", "data-source"=choices, style=style,
- "data-items"=items, "data-minLength"=1, autocomplete="off",
- placeholder=label, value = value)))
-
-}
-
-# Update a typeahead element from server.R
-updateTypeAhead <- function(session, inputId, label=NULL, value=NULL, choices=NULL) {
-
- data <- dropNulls(list(label=label, value=value, choices=choices))
-
- session$sendInputMessage(inputId, data)
-
-}
\ No newline at end of file
diff --git a/R/bsTypeahead.R b/R/bsTypeahead.R
new file mode 100644
index 0000000..bd05652
--- /dev/null
+++ b/R/bsTypeahead.R
@@ -0,0 +1,41 @@
+#'bsTypeahead
+#'
+#'\code{typeaheadInput} creates a textinput with type ahead function buttons.
+#'
+#'@param inputId Input variable to assign the control's value to
+#'@param label Display label for the control
+#'@param value Initial value
+#'@param choices Array of strings to match against. Can also be JavaScript
+#' function. Use htmlwidgets::JS() to indicate JavaScript. The length of \code{choices} must no exceed 131370.
+#'@param items The max number of items to display in the dropdown. Can also be
+#' set to 'all'
+#'@param minLength The minimum character length needed before triggering
+#' autocomplete suggestions. You can set it to 0 so suggestion are shown even
+#' when there is no text when lookup function is called.
+#'@seealso \code{\link{updateTypeaheadInput}}
+#'@export
+bsTypeahead <- function(inputId, label, value = "", choices, items = 8, minLength = 1) {
+ if(!is.null(choices)) {
+ if(length(choices) > 131370) {
+ warning("Due to a limitation of the Bootstrap2 Typeahead JavaScript library the length of 'choices' must not exceed 2 ^ 17 - 2!");
+ }
+ }
+ if(!'JS_EVAL' %in% class(choices)) {
+ choices <- jsonlite::toJSON(choices);
+ }
+ typeahead <- shiny::tagList(
+ shiny::div(class = 'form-group shiny-input-container',
+ shiny::tags$label(label, `for` = inputId),
+ shiny::tags$input(id = inputId, type="text",
+ class="form-control shiny-bound-input typeahead",
+ "data-provide" = "typeahead", autocomplete="off",
+ value = value),
+ shiny::tags$script(paste0("$('#", inputId, "').typeahead({source: ", choices, ",
+ items: ", items, ",
+ minLength: ", minLength, "})"))
+ )
+ )
+
+ htmltools::attachDependencies(typeahead, typeaheadDep)
+
+}
\ No newline at end of file
diff --git a/R/closeAlert.R b/R/closeAlert.R
new file mode 100644
index 0000000..f96b328
--- /dev/null
+++ b/R/closeAlert.R
@@ -0,0 +1,18 @@
+#'closeAlert
+#'
+#'\code{closeAlert} is used within your Server logic to close an alert that you
+#'created with \code{\link{createAlert}}.
+#'
+#'@param alertId The id of the alert to be dismissed.
+#'@inheritParams createAlert
+#'
+#'@templateVar item_name closeAlert
+#'@templateVar family_name Alerts
+#'@template item_details
+#'@template footer
+#'@export
+closeAlert <- function(session, alertId) {
+
+ session$sendCustomMessage(type="bsAlertClose", alertId)
+
+}
\ No newline at end of file
diff --git a/R/createAlert.R b/R/createAlert.R
new file mode 100644
index 0000000..16d8807
--- /dev/null
+++ b/R/createAlert.R
@@ -0,0 +1,30 @@
+#'createAlert
+#'
+#'\code{createAlert} is used within the Server logic of your Shiny app to display
+#'an alert to the user.
+#'
+#'@param session The session object passed to function given to shinyServer.
+#'@param anchorId The unique identifier of the anchor where the alert should be
+#'displayed.
+#'@param alertId \bold{Optional} A unique identifier for the Alert.
+#'@param title \bold{Optional} A title for the Alert.
+#'@param content The main body of the Alert. HTML tags are allowed.
+#'@param style A bootstrap style to apply. Defaults to \code{info}.
+#'@param dismiss \code{logical} Should the Alert be user dismissable? Defaults to \code{TRUE}.
+#'@param append \code{logical} Should the Alert be appended below existing Alerts? Default to \code{TRUE}.
+#'
+#'@templateVar item_name createAlert
+#'@templateVar family_name Alerts
+#'@template item_details
+#'@template footer
+#'@export
+createAlert <- function(session, anchorId, alertId = NULL, title=NULL,
+ content=NULL, style=NULL, dismiss=TRUE, append=TRUE) {
+
+ data <- dropNulls(list(id = anchorId, alertId = alertId, title = title,
+ content = content, style = style, dismiss = dismiss,
+ append = append))
+
+ session$sendCustomMessage(type="bsAlertCreate", data)
+
+}
diff --git a/R/misc.R b/R/misc.R
index 3623693..3238633 100644
--- a/R/misc.R
+++ b/R/misc.R
@@ -1,40 +1,16 @@
.onAttach <- function(...) {
# Create link to javascript and css files for package
- addResourcePath("sbs", system.file("www", package="shinyBS"))
+ shiny::addResourcePath("sbs", system.file("www", package="shinyBS"))
}
-# Wrapper to add the appropriate singletons to the head of the shiny app
-sbsHead <- function(...) {
-
- tagList(singleton(tags$head(tags$script(src = "sbs/shinyBS.js"),
- tags$link(rel = "stylesheet", type = "text/css", href = "sbs/shinyBS.css"))),
- ...
- )
-}
+shinyBSDep <- htmltools::htmlDependency("shinyBS", packageVersion("shinyBS"), src = c("href" = "sbs"), script = "shinyBS.js", stylesheet = "shinyBS.css")
+typeaheadDep <- htmltools::htmlDependency("shinyBS", packageVersion("shinyBS"), src = c("href" = "sbs"), script = c("bootstrap3-typeahead.js", "typeahead_inputbinding.js"));
# Copy of dropNulls function for shiny to avoid using shiny:::dropNulls
dropNulls <- function(x) {
- x[!vapply(x, is.null, FUN.VALUE = logical(1))]
-}
-
-# Takes a tag and removes any classes in the remove argument
-removeClass <- function(tag, remove) {
-
- if(length(remove) == 1) remove <- strsplit(remove, " ", fixed = TRUE)[[1]]
-
- class <- strsplit(tag$attribs$class, " ", fixed = TRUE)[[1]]
- class <- class[!(class %in% remove)]
- tag$attribs$class <- paste(class, collapse = " ")
-
- return(tag)
-
-}
-
-addClass <- function(tag, add) {
- tag$attribs$class <- paste(tag$attribs$class, add)
- return(tag)
+ x[!vapply(x, is.null, FUN.VALUE = logical(1))]
}
addAttribs <- function(tag, ...) {
@@ -53,27 +29,6 @@ removeAttribs <- function(tag, ...) {
return(tag)
}
-inputCheck <- function(..., valid, stop.func = FALSE) {
-
- v <- list(...)[1]
-
- if(!(v %in% valid)) {
-
- n <- names(list(...))[1]
- caller <- deparse(sys.call(-1)[1])
- msg <- paste0("Invalid '", n, "' argument in ", caller, ": ", v)
- if(stop.func) {
- stop(msg, call. = FALSE)
- } else {
- warning(msg, call. = FALSE)
- }
-
- return(FALSE)
-
- } else {
-
- return(TRUE)
-
- }
-
+getAttribs <- function(tag) {
+ tag$attribs
}
diff --git a/R/popify.R b/R/popify.R
new file mode 100644
index 0000000..1020145
--- /dev/null
+++ b/R/popify.R
@@ -0,0 +1,36 @@
+#'popify
+#'
+#'\code{popify} can be wrapped around any shiny UI element to add a popover to the
+#'wrapped element. This should be a safer way to add popovers to elements created with
+#'\code{\link{renderUI}}.
+#'
+#'@param el A shiny UI element.
+#'@param title The title of the popover.
+#'@param content The main content of the popover.
+#'@param placement Where the popover should appear relative to its target
+#'(\code{top}, \code{bottom}, \code{left}, or \code{right}). Defaults to \code{"bottom"}.
+#'@param trigger What action should cause the popover to appear? (\code{hover},
+#'\code{focus}, \code{click}, or \code{manual}). Defaults to \code{"hover"}.
+#'@param options A named list of additional options to be set on the popover.
+#'
+#'@templateVar item_name popify
+#'@templateVar family_name Tooltips_and_Popovers
+#'@template item_details
+#'@template footer
+#'@export
+popify <- function(el, title, content, placement="bottom", trigger="hover", options = NULL) {
+
+ id <- el$attribs$id
+
+ if(is.null(id)) {
+ id <- paste0("tipify", as.integer(runif(1, 1, 10000000)))
+ el <- addAttribs(el, id = id)
+ }
+
+ options = buildTooltipOrPopoverOptionsList(title, placement, trigger, options, content)
+
+ script <- createTooltipOrPopoverOnUI(id, "popover", options)
+
+ return(shiny::tagList(el, script))
+
+}
\ No newline at end of file
diff --git a/R/removePopover.R b/R/removePopover.R
new file mode 100644
index 0000000..024d1de
--- /dev/null
+++ b/R/removePopover.R
@@ -0,0 +1,18 @@
+#'removePopover
+#'
+#'\code{removePopover} is used within the Server logic of an app to remove an
+#'existing popover from a Shiny input or output.
+#'
+#'@param session The session object passed to function given to shinyServer.
+#'@param id The id of the element to remove the popover from.
+#'
+#'@templateVar item_name removePopover
+#'@templateVar family_name Tooltips_and_Popovers
+#'@template item_details
+#'@template footer
+#'@export
+removePopover <- function(session, id) {
+
+ session$sendCustomMessage(type="updateTooltipOrPopover", list(action = "remove", type = "popover", id = id))
+
+}
\ No newline at end of file
diff --git a/R/removeTooltip.R b/R/removeTooltip.R
new file mode 100644
index 0000000..51ae00e
--- /dev/null
+++ b/R/removeTooltip.R
@@ -0,0 +1,18 @@
+#'removeTooltip
+#'
+#'\code{removeTooltip} is used within the Server logic of an app to remove an
+#'existing tooltip from a Shiny input or output.
+#'
+#'@param session The session object passed to function given to shinyServer.
+#'@param id The id of the element to remove the tooltip from.
+#'
+#'@templateVar item_name removeTooltip
+#'@templateVar family_name Tooltips_and_Popovers
+#'@template item_details
+#'@template footer
+#'@export
+removeTooltip <- function(session, id) {
+
+ session$sendCustomMessage(type="updateTooltipOrPopover", list(action = "remove", type = "tooltip", id = id))
+
+}
\ No newline at end of file
diff --git a/R/tagManipulators.R b/R/tagManipulators.R
new file mode 100644
index 0000000..a2ad0fe
--- /dev/null
+++ b/R/tagManipulators.R
@@ -0,0 +1,96 @@
+addClass <- function(tag, class) {
+
+ if(!is.null(class)) {
+ tag$attribs$class <- trimws(paste(tag$attribs$class, class), "both")
+ }
+
+ tag
+
+}
+
+removeClass <- function(tag, class) {
+
+ if(!is.null(class) & !is.null(tag$attribs$class)) {
+ cls <- strsplit(tag$attribs$class, " ")[[1]]
+ cls <- cls[cls != class]
+ tag$attribs$class <- paste(cls, collapse = " ")
+ }
+
+ tag
+
+}
+
+hasClass <- function(tag, class) {
+ if(!is.null(class) & !is.null(tag$attribs$class)) {
+ class %in% strsplit(tag$attribs$class, " ")[[1]]
+ } else {
+ FALSE
+ }
+}
+
+checkClass <- function(class, include) {
+ if(!include) class <- NULL
+ class
+}
+
+buildClass <- function(prefix, variable) {
+ if(!is.null(variable)) {
+ variable <- paste0(prefix, variable)
+ }
+ variable
+}
+
+addStyles <- function(tag, ..., .dots) {
+
+ new_styles <- list(...)
+
+ if(!missing(.dots)) {
+ new_styles <- c(new_styles, .dots)
+ }
+
+ if(!is.null(tag$attribs$style)) {
+ styles <- parseStyles(tag$attribs$style)
+ } else {
+ styles <- list()
+ }
+
+ for(i in seq_along(new_styles)) {
+ styles[[names(new_styles)[i]]] <- new_styles[[i]]
+ }
+
+ tag$attribs$style <- writeStyles(styles)
+
+ tag
+
+}
+
+removeStyles <- function(tag, ...) {
+
+ if(!is.null(tag$attribs$style)) {
+ styleList <- list(...)
+ styles <- parseStyles(tag$attribs$style)
+ styles <- styles[!names(styles) %in% styleList]
+ tag$attribs$style <- writeStyles(styles)
+ }
+
+ tag
+
+}
+
+parseStyles <- function(styleString) {
+
+ styles <- trimws(strsplit(styleString, ";")[[1]])
+ styles <- strsplit(styles, ":")
+ style_names <- sapply(styles, function(s) trimws(s[1]))
+ styles <- lapply(styles, function(s) trimws(s[2]))
+ names(styles) <- style_names
+
+ return(styles)
+
+}
+
+writeStyles <- function(styleList) {
+
+ paste(names(styleList), styleList, sep = ": ", collapse = "; ")
+
+}
diff --git a/R/tipify.R b/R/tipify.R
new file mode 100644
index 0000000..659d53f
--- /dev/null
+++ b/R/tipify.R
@@ -0,0 +1,35 @@
+#'tipify
+#'
+#'\code{tipify} can be wrapped around any shiny UI element to add a tooltip to the
+#'wrapped element. This should be a safer way to add tooltips to elements created with
+#'\code{\link{renderUI}}.
+#'
+#'@param el A shiny UI element.
+#'@param title The content of the tooltip.
+#'@param placement Where the tooltip should appear relative to its target
+#'(\code{top}, \code{bottom}, \code{left}, or \code{right}). Defaults to \code{"bottom"}.
+#'@param trigger What action should cause the tooltip to appear? (\code{hover},
+#'\code{focus}, \code{click}, or \code{manual}). Defaults to \code{"hover"}.
+#'@param options A named list of additional options to be set on the tooltip.
+#'
+#'@templateVar item_name tipify
+#'@templateVar family_name Tooltips_and_Popovers
+#'@template item_details
+#'@template footer
+#'@export
+tipify <- function(el, title, placement="bottom", trigger="hover", options = NULL) {
+
+ id <- el$attribs$id
+
+ if(is.null(id)) {
+ id <- paste0("tipify", as.integer(runif(1, 1, 10000000)))
+ el <- addAttribs(el, id = id)
+ }
+
+ options = buildTooltipOrPopoverOptionsList(title, placement, trigger, options)
+
+ script <- createTooltipOrPopoverOnUI(id, "tooltip", options)
+
+ return(shiny::tagList(el, script))
+
+}
\ No newline at end of file
diff --git a/R/toggleModal.R b/R/toggleModal.R
new file mode 100644
index 0000000..3621535
--- /dev/null
+++ b/R/toggleModal.R
@@ -0,0 +1,19 @@
+#'toggleModal
+#'
+#'\code{toggleModal} is used within your Server logic to open or close a modal
+#'window.
+#'
+#'@param session The session object passed to function given to shinyServer.
+#'@param modalId The id of the modal window you want to open/close
+#'@param toggle Should the modal window \code{open}, \code{close}, or \code{toggle}?
+#'
+#'@templateVar item_name toggleModal
+#'@templateVar family_name Modals
+#'@template item_details
+#'@template footer
+#'@export
+toggleModal <- function(session, modalId, toggle = "toggle") {
+
+ session$sendInputMessage(modalId, list(toggle = toggle))
+
+}
\ No newline at end of file
diff --git a/R/updateButton.R b/R/updateButton.R
new file mode 100644
index 0000000..03f0c78
--- /dev/null
+++ b/R/updateButton.R
@@ -0,0 +1,37 @@
+#'updateButton
+#'
+#'\code{updateButton} is used in your Server logic to update the style or state
+#'of a button.
+#'
+#'@inheritParams bsButton
+#'@param session The session object passed to function given to shinyServer.
+#'
+#'@details Because of the way it is coded, \code{updateButton} may work on buttons not
+#'created by \code{\link{bsButton}} such as \code{\link{submitButton}}.
+#'
+#'See \code{\link{Buttons}} for more information about how to use \code{updateButton} with the rest of the Buttons family.
+#'
+#'@templateVar item_name updateButton
+#'@templateVar family_name Buttons
+#'@template item_details
+#'@template footer
+#'@export
+updateButton <- function(session, inputId, label = NULL, icon = NULL, value = NULL, style = NULL,
+ size = NULL, block = NULL, disabled = NULL) {
+
+ if(!is.null(icon)) icon <- as.character(icon)
+
+ if(!is.null(size)) {
+ size <- switch(size,
+ "extra-small" = "btn-xs",
+ "small" = "btn-sm",
+ "large" = "btn-lg",
+ "default" = "default")
+ }
+
+ data <- dropNulls(list(id = inputId, label = label, icon = icon, value = value, style = style,
+ size = size, block = block, disabled = disabled))
+
+ session$sendCustomMessage("bsButtonUpdate", data)
+
+}
\ No newline at end of file
diff --git a/R/updateCollapse.R b/R/updateCollapse.R
new file mode 100644
index 0000000..000dff2
--- /dev/null
+++ b/R/updateCollapse.R
@@ -0,0 +1,27 @@
+#'updateCollapse
+#'
+#'\code{updateCollapse} is used within the Server logic of your Shiny app to
+#'modify a Collapse after load.
+#'
+#'@param session The session object passed to function given to shinyServer.
+#'@param id The id of the Collapse object you want to change.
+#'@param open A vector of \code{value} (or \code{title} if no \code{value} was
+#'provided) values identifying the panels you want to open.
+#'@param close A vector of \code{value} (or \code{title} if no \code{value} was
+#'provided) values identifying the panels you want to close.
+#'@param style A named list of Bootstrap styles (\code{primary}, \code{danger}, \code{info},
+#'\code{warning}, \code{success}, or \code{default}). The names should correspond
+#'to the \code{value} (or \code{title} if no \code{value} was provided) of the
+#'\code{\link{bsCollapsePanel}} you want to change.
+#'
+#'@templateVar item_name updateCollapse
+#'@templateVar family_name Collapses
+#'@template item_details
+#'@template footer
+#'@export
+updateCollapse <- function(session, id, open = NULL, close = NULL, style = NULL) {
+
+ data <- dropNulls(list(open = open, close = close, style = style))
+ session$sendInputMessage(id, data)
+
+}
\ No newline at end of file
diff --git a/R/updateTypeahead.R b/R/updateTypeahead.R
new file mode 100644
index 0000000..8acadba
--- /dev/null
+++ b/R/updateTypeahead.R
@@ -0,0 +1,23 @@
+#'updateTypeahead
+#'
+#'\code{updateTypeahead} Update a typeaheadInput buttons.
+#'@param session The session object passed to function given to shinyServer.
+#'@param inputId Input variable to assign the control's value to
+#'@param label Display label for the control
+#'@param value Initial value
+#'@param choices Array of strings to match against. Can also be JavaScript
+#' function. Use htmlwidgets::JS() to indicate JavaScript.
+#'@seealso \code{\link{typeaheadInput}}
+#'@export
+updateTypeahead<- function(session, inputId, label=NULL, value=NULL, choices=NULL) {
+
+ if(!is.null(choices)) {
+ if(length(choices) > 131370) {
+ warning("Due to a limitation of the Bootstrap2 Typeahead JavaScript library the length of 'choices' must not exceed 2 ^ 17 - 2!");
+ }
+ }
+
+ data <- dropNulls(list(id = inputId, label=label, value=value, choices=choices))
+ session$sendCustomMessage("typeaheadUpdate", data)
+
+}
diff --git a/README.md b/README.md
index bf713ad..d4bd08e 100644
--- a/README.md
+++ b/README.md
@@ -8,70 +8,34 @@ Eric
shinyBS
-------
-**shinyBS** is a package that adds several additional Twitter Boostrap components to shiny.
-You can install shinyBS from this repository by first installing `devtools`. At the R prompt type:
+**shinyBS** is a package that adds several additional Twitter Boostrap
+components to shiny. In January RStudio updated shiny to work with Bootstrap3
+which completely broke the original shinyBS. I have updated shinyBS to
+work with the newest versions of shiny.
-```
-install.packages("devtools")
-```
-
-After installing `devtools` in R you can install shinyBS by typing at the R prompt:
-
-```
-install_github("shinyBS", "ebailey78")
-```
-
-`shinyBS` was also added to CRAN. You can install the CRAN version with:
+After several rounds of revisions, shinyBS v0.61 was accepted by CRAN on March 31st, 2015 and is available for install with `install.packages()`
-```
+```R
install.packages("shinyBS")
```
-For a quick demonstration of `shinyBS` functionality run the following code at the R prompt:
-
-```
-library(shinyBS)
-bsDemo()
-```
-
-### What's New
-
-#### Version 0.25 (working version)
-
-* **bsNavDropDown**
- * You can now create submenus inside a drop down by making a including lists inside your choices argument list. The submenus are built recursively so theoretically submenus can go as deep as you want
- * You can create headers and dividers in your menus by include `NA`'s in you choices list, a named `NA` will become a header and an unnamed `NA` will become a divider.
- * You can create dropdowns with media objects as their options. This is done with the `bsMedia()` function.
- * I am working on a bsNavDemo() example that will better explain changes to dropdowns.
-* **bsModal**
- * You can now create modal windows with the `bsModal()` function. These are trigger from a button or link and can contain any combination of inputs, outputs, or standard html.
-* **Table Highlighting**
- * Per Request: highlightCells() now accepts a `column` argument which limits cell highlighting to that column.
+Not all functionality that was in the previous versions was kept in this new version. Partly because of time constraints and partly because of some functionality being removed from Bootstrap.
-#### Version 0.20 (released: 2014-03-19)
+Features that remain in shinyBS 0.61 include:
-* **pageWithNavBar**
- * I forgot to include the pageWithNavbar function in the NAMESPACE file so it wasn't exported
-* **Buttons/Button Groups**
- * singletons for including shinyBS's javascript and CSS files weren't added when only button functions were included in an app
- * added `block` argument for creating block level buttons and button groups
- * added `vertical` argument for creating verically oriented button groups
-
-* **Tooltips/Popovers**
- * Tooltips and Popovers will now work with the new selectize-type selectInput's in shiny 0.9.0
-* **Tables**
- * `highlightCells` lets you highlight table cells based on their content
- * `highlightRows` lets you highlight table rows based on the content of a table column
+* Alerts
+* Tooltips
+* Popovers
+* Modal Windows
+* Collapse Panels
+* Button upgrades
-#### Version 0.10 (released: 2014-03-11)
+Features that are not included in shinyBS 0.61 include:
-* **Alerts** - Create alert anchors in your `ui.R` script and add alerts from `server.R`
-* **Tooltips** - Add and configure tooltips on any element with an `inputId` or `outputId` with `bsTooltip()` from the ui or with `addToolTip()` from the server.
-* **Popovers** - Works the same as Tooltips but useful for more content heavy applications.
-* **TypeAhead** - Works just like a 'textInput' but you can provide custom autocomplete lists to guide the user to specific inputs.
-* **Progress Bars** - Fully configurable Progress bars that can be updated and changed from `server.R`.
-* **Navigation Bars** - Create Bootstrap style navigation bars with buttons, links, dropdowns, etc that control your shiny app.
-* **Collapse Panels** - Create collapsable panels that allow you to remove some clutter from your app.
-* **Buttons Groups** - Create button groups that behave like radio buttons or checkbox groups
-* **Buttons** - Access Twitter Bootstrap styles and sizes for action buttons and toggle buttons
+* Navbars and related components
+* Typeaheads
+* Progress Bars
+* Button Groups
+* Table Formatting
+Now that this version has been been accepted by CRAN I will start working on updates and added functionality. If you have a request please open an issue and let me know. Thanks!
diff --git a/inst/examples/Alerts/server.R b/inst/examples/Alerts/server.R
new file mode 100644
index 0000000..b1eee03
--- /dev/null
+++ b/inst/examples/Alerts/server.R
@@ -0,0 +1,22 @@
+library(shiny)
+library(shinyBS)
+shinyServer(
+ function(input, output, session) {
+ output$exampleOutput <- renderText({
+ num1 <- as.numeric(input$num1)
+ num2 <- as.numeric(input$num2)
+
+ if(is.na(num1) | is.na(num2)) {
+ createAlert(session, "alert", "exampleAlert", title = "Oops",
+ content = "Both inputs should be numeric.", append = FALSE)
+ } else if(num2 == 0) {
+ createAlert(session, "alert", "exampleAlert", title = "Oops",
+ content = "You cannot divide by 0.", append = FALSE)
+ } else {
+ closeAlert(session, "exampleAlert")
+ return(num1/num2)
+ }
+
+ })
+ }
+)
diff --git a/inst/examples/Alerts/ui.R b/inst/examples/Alerts/ui.R
new file mode 100644
index 0000000..6378a91
--- /dev/null
+++ b/inst/examples/Alerts/ui.R
@@ -0,0 +1,13 @@
+library(shiny)
+library(shinyBS)
+ fluidPage(
+ sidebarLayout(
+ sidebarPanel(textInput("num1", NULL, value = 100),
+ "divided by", textInput("num2", NULL, value = 20),
+ "equals", textOutput("exampleOutput")),
+ mainPanel(
+ bsAlert("alert")
+ )
+ )
+)
+
diff --git a/inst/examples/Buttons/server.R b/inst/examples/Buttons/server.R
new file mode 100644
index 0000000..e0a21c1
--- /dev/null
+++ b/inst/examples/Buttons/server.R
@@ -0,0 +1,49 @@
+library(shiny)
+library(shinyBS)
+shinyServer(
+ function(input, output, session) {
+ observeEvent(input$togOne, ({
+ updateButton(session, "actOne", disabled = !input$togOne)
+ }))
+ observeEvent(input$bins, ({
+
+ b <- input$bins
+ disabled = NULL
+ style = "default"
+ icon = ""
+
+ if(b < 5) {
+ disabled = TRUE
+ icon <- icon("ban")
+ } else {
+ disabled = FALSE
+ }
+
+ if(b < 15 | b > 35) {
+ style = "danger"
+ } else if(b < 20 | b > 30) {
+ style = "warning"
+ } else {
+ style = "default"
+ icon = icon("check")
+ }
+
+ updateButton(session, "actTwo", disabled = disabled, style = style, icon = icon)
+
+ }))
+
+ output$exampleText <- renderText({
+ input$actTwo
+ b <- isolate(input$bins)
+ txt = ""
+ if((b > 5 & b < 15) | b > 35) {
+ txt = "That was dangerous."
+ } else if((b > 5 & b < 20) | b > 30) {
+ txt = "I warned you about that."
+ } else if(b >= 20 & b <= 30) {
+ txt = "You have chosen... wisely."
+ }
+ return(txt)
+ })
+ }
+)
diff --git a/inst/examples/Buttons/ui.R b/inst/examples/Buttons/ui.R
new file mode 100644
index 0000000..7b37a05
--- /dev/null
+++ b/inst/examples/Buttons/ui.R
@@ -0,0 +1,23 @@
+library(shiny)
+library(shinyBS)
+ fluidPage(
+ sidebarLayout(
+ sidebarPanel(
+ sliderInput("bins",
+ "Move the slider to see its effect on the button below:",
+ min = 1,
+ max = 50,
+ value = 1),
+ bsButton("actTwo", label = "Click me if you dare!", icon = icon("ban")),
+ tags$p("Clicking the first button below changes the disabled state of the second button."),
+ bsButton("togOne", label = "Toggle button disabled status",
+ block = TRUE, type = "toggle", value = TRUE),
+ bsButton("actOne", label = "Block Action Button", block = TRUE)
+
+ ),
+ mainPanel(
+ textOutput("exampleText")
+ )
+ )
+)
+
diff --git a/inst/examples/Collapses/server.R b/inst/examples/Collapses/server.R
new file mode 100644
index 0000000..c2fac84
--- /dev/null
+++ b/inst/examples/Collapses/server.R
@@ -0,0 +1,13 @@
+library(shiny)
+library(shinyBS)
+shinyServer(
+ function(input, output, session) {
+ output$genericPlot <- renderPlot(plot(rnorm(100)))
+ observeEvent(input$p1Button, ({
+ updateCollapse(session, "collapseExample", open = "Panel 1")
+ }))
+ observeEvent(input$styleSelect, ({
+ updateCollapse(session, "collapseExample", style = list("Panel 1" = input$styleSelect))
+ }))
+ }
+)
diff --git a/inst/examples/Collapses/ui.R b/inst/examples/Collapses/ui.R
new file mode 100644
index 0000000..0dd53a7
--- /dev/null
+++ b/inst/examples/Collapses/ui.R
@@ -0,0 +1,21 @@
+library(shiny)
+library(shinyBS)
+ fluidPage(
+ sidebarLayout(
+ sidebarPanel(HTML("This button will open Panel 1 using updateCollapse."),
+ actionButton("p1Button", "Push Me!"),
+ selectInput("styleSelect", "Select style for Panel 1",
+ c("default", "primary", "danger", "warning", "info", "success"))
+ ),
+ mainPanel(
+ bsCollapse(id = "collapseExample", open = "Panel 2",
+ bsCollapsePanel("Panel 1", "This is a panel with just text ",
+ "and has the default style. You can change the style in ",
+ "the sidebar.", style = "info"),
+ bsCollapsePanel("Panel 2", "This panel has a generic plot. ",
+ "and a 'success' style.", plotOutput("genericPlot"), style = "success")
+ )
+ )
+ )
+)
+
diff --git a/inst/examples/Modals/server.R b/inst/examples/Modals/server.R
new file mode 100644
index 0000000..174fde5
--- /dev/null
+++ b/inst/examples/Modals/server.R
@@ -0,0 +1,33 @@
+library(shiny)
+library(shinyBS)
+shinyServer(
+ function(input, output, session) {
+
+ output$distPlot <- renderPlot({
+
+ x <- faithful[, 2]
+ bins <- seq(min(x), max(x), length.out = input$bins + 1)
+
+ # draw the histogram with the specified number of bins
+ hist(x, breaks = bins, col = 'darkgray', border = 'white')
+
+ })
+
+ output$distTable <- renderDataTable({
+
+ x <- faithful[, 2]
+ bins <- seq(min(x), max(x), length.out = input$bins + 1)
+
+ # draw the histogram with the specified number of bins
+ tab <- hist(x, breaks = bins, plot = FALSE)
+ tab$breaks <- sapply(seq(length(tab$breaks) - 1), function(i) {
+ paste0(signif(tab$breaks[i], 3), "-", signif(tab$breaks[i+1], 3))
+ })
+ tab <- as.data.frame(do.call(cbind, tab))
+ colnames(tab) <- c("Bins", "Counts", "Density")
+ return(tab[, 1:3])
+
+ }, options = list(pageLength=10))
+
+ }
+)
diff --git a/inst/examples/Modals/ui.R b/inst/examples/Modals/ui.R
new file mode 100644
index 0000000..bc0170a
--- /dev/null
+++ b/inst/examples/Modals/ui.R
@@ -0,0 +1,21 @@
+library(shiny)
+library(shinyBS)
+ fluidPage(
+ sidebarLayout(
+ sidebarPanel(
+ sliderInput("bins",
+ "Number of bins:",
+ min = 1,
+ max = 50,
+ value = 30),
+ actionButton("tabBut", "View Table")
+ ),
+
+ mainPanel(
+ plotOutput("distPlot"),
+ bsModal("modalExample", "Data Table", "tabBut", size = "large",
+ dataTableOutput("distTable"))
+ )
+ )
+)
+
diff --git a/inst/examples/TooltipsandPopovers/server.R b/inst/examples/TooltipsandPopovers/server.R
new file mode 100644
index 0000000..d7de9e2
--- /dev/null
+++ b/inst/examples/TooltipsandPopovers/server.R
@@ -0,0 +1,33 @@
+library(shiny)
+library(shinyBS)
+shinyServer(
+ function(input, output, session) {
+ output$distPlot <- renderPlot({
+
+ # generate bins based on input$bins from ui.R
+ x <- faithful[, 2]
+ bins <- seq(min(x), max(x), length.out = input$bins + 1)
+
+ # draw the histogram with the specified number of bins
+ hist(x, breaks = bins, col = 'darkgray', border = 'white')
+
+ })
+ output$dataTable <- renderDataTable({
+ faithful
+ })
+ output$uiExample <- renderUI({
+ tags$span(
+ popify(bsButton("pointlessButton", "Button", style = "primary", size = "large"),
+ "A Pointless Button",
+ "This button is pointless. It does not do anything!"),
+ tipify(bsButton("pB2", "Button", style = "inverse", size = "extra-small"),
+ "This button is pointless too!")
+ )
+ })
+ addPopover(session, "distPlot", "Data", content = paste0("
Waiting time between ",
+ "eruptions and the duration of the eruption for the Old Faithful geyser ",
+ "in Yellowstone National Park, Wyoming, USA.
Azzalini, A. and ",
+ "Bowman, A. W. (1990). A look at some data on the Old Faithful geyser. ",
+ "Applied Statistics 39, 357-365.
I've created bsDemo() to hopefully help reduce the learning curve for using shinyBS by allowing you to interact with new components directly within a shiny application rather than having to have to rely soley on the help files in R. Each added component is represented by a tab above. Clicking a tab will display a demonstration panel for the component. Each panel is laid out like the example on the right. A brief explanation of a panel follows:")),
- tags$ul(tags$li("The upper-left section of the panel contains brief explanatory text for the component."),
- tags$li("The upper-right section contains a minimal example of how the component could be implemented in a ui.R script."),
- tags$li("The lower-right section contains a minimal example of how the component could be implemented or updated from a server.R script."),
- tags$li("The lower-middle section contains an interactive example of the component."),
- tags$li("The lower-left section contains a control panel that allows you to see how changes to the arguments of the component affect the appearance and/or behavior in the example component. The code contained in the ui.R and server.R scripts will also update to reflect the changes you make in the control panel.")
- ),
- tags$p(HTML("Please use the tabs above to explore shinyBS functionality. I have made great efforts to make sure that the code all works under multiple use scenarios but if you find a bug, or if you have suggestions for additional functionality, please contact me at ebailey@idem.in.gov."))
-
- ),
- tags$div(class = "span6", tags$img(src="expic.png")))),
-##### Navbar Demo #####
- demoPanel(title = "Navbars",
- intro = paste0("
Navbars offer a space-efficient way to group your inputs together in your shiny app. Most of the customizations in Twitter Bootstrap are available as arguments in the bsNavBar() function. Any element you add to the navbar will align to the left, unless you add them to the rightItems argument, which will cause them to align to the right.
",
- "
Several of shiny's default inputs have been reformatted to look better in the navbar. For example, textInput has had its label changed to a placeholder and has an added 'width' attribute to help save room. New versions of inputs have had bsNav prepended to their names.
",
- "
Refer to the help files for shinyBS for additional information about navBar inputs.
Alerts allow you to communicate information to the user on the fly. Begin by creating an alert anchor with the bsAlert() function in the iu.R script. You can then add alerts to this anchor with createAlert() and remove them with closeAlert().
By default, new alerts are placed below any alerts already present in the alert anchor but if you set append = FALSE in createAlert() the new alert will overwrite any existing alerts.
Also by default, alerts will be dismissable by the user with a small × in the upper-right corner of the alert. You can override this behavior by setting dismiss = FALSE in createAlert(). The alert can then only be removed using closeAlert() (be sure to set alertId when you create the alert) or by creating a new alert with append = FALSE in the same anchor.
Progress bars are created with the bsProgressBar() function in ui.R and then modified with updateProgressBar() in server.R.
If you don't want the progress bar to be present all the time you should still create it in your ui.R script but set visible = FALSE. You can then use updateProgressBar() to make it visible when you want it.
The easiest use for them would be in some sort of loop where you can add an updateProgressBar() to the code in the loop to reflect how much of the loop has completed.
The color argument corresponds to the same predefined classes that alerts have, with the addition of a darker blue 'standard' option.
TypeAhead boxes are special versions of textboxes that help lead the user to acceptable inputs. They are created with the bsTypeAhead() function and can be updated with updateTypeAhead(). You can set the minimum match length and number of items to display at creation, but these properties cannot be changed by updateTypeAhead().
The example below allows you to choose between three predefined vectors for the choice arugment but any reality any vector or list can be used.
Tooltips and popovers are added in very similar ways. Tooltips/Popovers can be added to any element with an inputId or an outputId by using bsTooltip() in ui.R, or addTooltip() in server.R. Similarly, you can remove tooltips and popovers from an object by using removeTooltip() and removePopover(), respectively.
Tooltips would generally be used to provide brief additional information about an input or output element. Popovers can contain much more detailed information but currently cannot contain shiny inputs or outputs. I hope to figure out how to incorporate them in a future release.
Some tooltips and popovers have already been added to the example below. These are used to illustrate how they can be added in the ui.R script. You can add your own tooltips and popovers from the control panel. The code for these will be shown in the server.R script.",
- controls = tagList(selectInput("tpTarget", "Target", c("link", "slider", "select", "text", "plot")),
- radioButtons("tpType", "Type", choices = c("Tooltip", "Popover"), selected= "Tooltip"),
- textInput("tpTitle", "Title", "A tooltip"),
- conditionalPanel("input.tpType == 'Popover'", textInput("tpContent", "Content", "This is content. Isn't it great!")),
- selectInput("tpPlacement", "Placement", c("top", "bottom", "left", "right")),
- radioButtons("tpTrigger", "Triggers", choices = c("click", "hover", "focus", "manual"), selected="hover"),
- actionButton("tpAdd", "Add")),
- example = tagList(tags$p(HTML("This is some example text. It is here so that I can put a link in the example. I've given the link an id attribute so that tooltips and popovers can be assigned to it. Otherwise this example is an expansion of the '01_Hello' example that is part of shiny. ")),
- tags$div(class = "row-fluid",
- tags$div(class = "span3 well control-panel",
- sliderInput("tpobs", "Number of observations:", min = 1, max = 1000, value = 500),
- selectInput("tpdist", "Distribution", choices = c("Normal", "Lognormal", "Uniform", "Exponential")),
- textInput("tptitle", "Plot Title", "A Plot")
- ),
- tags$div(class = "span9",
- plotOutput("tpplot")
- )
- ),
- bsTooltip("tpobs", "This changes the sample size of the random data set.", "right"),
- bsTooltip("tpdist", "This allows changes to the distribution", "right"),
- bsTooltip("tptitle", "Add a custom title to the plot", "right"),
- bsTooltip("tpplot", "Click plot to show popover", "top"),
- bsPopover("tpplot", "Boxplot", "I really wanted to have a boxplot based on the same dataset as the histogram appear in this box. Unfortunately, it appears that popovers are written when they are shown and destroyed when they are hidden so there is nothing persistent for shiny to bind to. So instead of a plot you get this text...", trigger="click", placement="right")
- ),
- uiCode = "tpUICode",
- serverCode = "tpServerCode"
- ),
-##### Collapse Demo #####
- demoPanel(title = "Collapse Panels",
- intro = "
Collapses (sometimes called accordions) are an alternative way to segment information and free up space in your shiny app. They have been designed to work in a very similar way to tabsetPanel() and tabPanel(). Create a collapse group with bsCollapse() and include any number of panels in it with bsCollapsePanel().
Similar to tabsetPanel(), bsCollapse() will return the value of the panel that is currently open. If multiple = TRUE then it will return an array of all open panel values.
You can use updateCollapse() to open and close panels or turn multiple on and off from server.R.
In some cases, collapse panels did not render properly when testing in Internet Explorer 10.
",
- controls = tagList(checkboxInput("coMult", "Multiple"),
- checkboxGroupInput("coOpen", "Open", c("Collapse #1" = "col1", "Collapse #2" = "col2", "Collapse #3" = "col3")),
- checkboxGroupInput("coClose", "Close", c("Collapse #1" = "col1", "Collapse #2" = "col2", "Collapse #3" = "col3")),
- actionButton("coUpdate", "Update"),
- tags$h5("Output"),
- textOutput("coValue")),
- example = bsCollapse(multiple = FALSE, open = c("col1"), id = "collapse1",
- bsCollapsePanel("Collapse #1", "Cell treachery spearwife night's watch, tower suckling pig, drink, your king commands it spare me your false courtesy tourney. Feed it to the goats, seven hells lord of light as high as honor in his cups. Sword greyscale old bear none so wise godswood the last of the dragons rouse me not. No foe may pass bloody mummers, let me soar spiced wine your grace honed and ready fire.", id="col1", value = "test1"),
- bsCollapsePanel("Collapse #2", actionButton("btn123", "A Button"), textInput("txt1234", "A Text Input"), id="col2", value = "test2"),
- bsCollapsePanel("Collapse #3", plotOutput("testPlot1"), id="col3", value = "test3")),
- uiCode = "coUICode",
- serverCode = "coServerCode"
- ),
-##### Buttons Demo #####
- demoPanel(title = "Buttons",
- intro = "
actionButtons are already a part of shiny but by using bsActionButton() you can create action buttons that can be sized and styled using Twitter Bootstrap's default styles (primary, info, success, warning, danger, inverse, and link) and sizes (large, small, and mini). You can also disable and enable the action button using the disabled argument at creation or in updateButton().
There is also a bsToggleButton() function that allows the creation of a button that can be toggled on/off; returning TRUE/FALSE depending on its current state. Toggle buttons can be styled the same as the action buttons previously mentioned.
Button Groups offer functionality similar to radioButtons() or checkBoxGroupInput(), depending on the value of the toggle argument. Create a button group by starting with bsButtonGroup() and adding bsButton() objects to it. Similar to how tabs are added in tabsetPanel(). Buttons in a button group can be individually styled, or if the style, size, or disabled argument is supplied to bsButtonGroup() these values will be applied to all buttons in the group.
These functions are experimental and may change significantly. The idea is to be able to highlight cells or rows based on their contents. You can match cells based on a numeric range with the min and max arguments or use the regex argument to use regular expresssions for cell matching.
highlightCells() is used for highlighting individual cells and highlightRows() is used for highlighting entire rows. Both functions use the same arguments with highlightRows() having an additional column argument for indicating the column to search. You can supply the column argument with the value that appears in the top row or with a numeric index value for the column. highlightCells() also has a skip.row.names argument for skipping the first column in a table.
Cells can be styled with the class or style arguments. class can be one of eight predefined classes (success, warning, error, info, good, bad, neutral, disabled) or any class you have defined. If you use the style argument its contents will be directly inserted into the style attribute of matching td and tr elements.
Modals are popup windows that can contain any html objects you want. You can either build the content of the modal window with R code or you can set the href argument to the location of a html file and have the html file loaded into the body of the modal.
Modals need to be linked to a button or anchor in the app. You create this link by setting the trigger argument in bsModal() to the id of the button or anchor you want to open the modal.
Modals are shiny inputs that return TRUE or FALSE based on whether they are currently visible.
You can open and/or close a modal from server.R by using the toggleModal() function.
This text comes from an html file in the www directory of the bsDemo app directory. By setting the href argument in bsModal() to this file's name, it was loaded into the body of the modal window. You could achieve a similar effect by using shiny's includeHTML() function.
-
-
-
-
\ No newline at end of file
diff --git a/inst/examples/navbar/server.R b/inst/examples/navbar/server.R
deleted file mode 100644
index 31434fb..0000000
--- a/inst/examples/navbar/server.R
+++ /dev/null
@@ -1,35 +0,0 @@
-library(shiny)
-library(shinyBS)
-
-ch <- list("Font Color" = list("White" = "txt:white", "Black" = "txt:black", "Red" = "txt:red", "Blue" = "txt:blue", "Green" = "txt:green", "Yellow" = "txt:yellow", "Orange" = "txt:orange", "Purple" = "txt:purple"),
- "Background Color" = list("White" = "bg:white", "Black" = "bg:black", "Red" = "bg:red", "Blue" = "bg:blue", "Green" = "bg:green", "Yellow" = "bg:yellow", "Orange" = "bg:orange", "Purple" = "bg:purple"))
-
-
-shinyServer(function(input, output, session) {
-
- output$test <- renderText({
-
- input$ndd1
-
- })
-
- observe({
-
- cmd <- unlist(strsplit(input$ndd1, ":"))
- if(length(cmd) > 0) {
- session$sendCustomMessage("options", list(option = cmd[1], value = cmd[2]))
- }
-
- })
-
- observe({
-
- if(input$test > 0) {
-
- updateDropDown(session, "ndd1", choices = ch)
-
- }
-
- })
-
-})
\ No newline at end of file
diff --git a/inst/examples/navbar/ui.R b/inst/examples/navbar/ui.R
deleted file mode 100644
index a1c8308..0000000
--- a/inst/examples/navbar/ui.R
+++ /dev/null
@@ -1,22 +0,0 @@
-library(shiny)
-library(shinyBS)
-
-options <- list("Font Size" = list("8pt" = "txtsz:8", "10pt" = "txtsz:10", "12pt" = "txtsz:12", "14pt" = "txtsz:14", "16pt" = "txtsz:16", "18pt" = "txtsz:18"),
- "Font Color" = list("White" = "txt:white", "Black" = "txt:black", "Red" = "txt:red", "Blue" = "txt:blue", "Green" = "txt:green", "Yellow" = "txt:yellow", "Orange" = "txt:orange", "Purple" = "txt:purple"),
- "Background Color" = list("White" = "bg:white", "Red" = "bg:red", "Blue" = "bg:blue", "Green" = "bg:green", "Yellow" = "bg:yellow", "Orange" = "bg:orange", "Purple" = "bg:purple"))
-media <- list(GI = bsMedia("GI", "Gary IITRI", "Gary IITRI has been an active monitor since 1998. Besides air toxics, Gary IITRI also monitors meteorology paramaters and criteria pollutants. Gary IITRI is also an unofficial PAMS monitor so it has hourly data for may air toxics.", "holder.js/100x100"),
- NE = bsMedia("NE", "Falls of the Ohio", "The Falls of the Ohio air toxics monitor is one of the newer monitors in the ToxWatch network, only active since 2008. It is located on the roof of the State Park visitors center and collects only 1-in-6 day toxics samples.", "holder.js/100x100/sky"))
-
-
-shinyUI(pageWithNavBar("NavBar Demo",
- navbar = bsNavBar("mainnb", "navBar Demo",
- bsNavDropDown("ndd1", "Options", options),
- bsNavDropDown("ndd2", "Monitors", media)
- ),
- tagList(tags$head(tags$script(src = "nbDemo.js"),
- tags$script(src = "holder/holder.js")),
- suppressWarnings(includeHTML("http://www.gameofipsum.com/api/?type=html¶graphs=5&percent=0")),
- bsActionButton("test", "Test", size = "large", style = "primary")
- )
- )
- )
\ No newline at end of file
diff --git a/inst/examples/navbar/www/holder/holder.js b/inst/examples/navbar/www/holder/holder.js
deleted file mode 100644
index d2fe17f..0000000
--- a/inst/examples/navbar/www/holder/holder.js
+++ /dev/null
@@ -1,658 +0,0 @@
-/*!
-
-Holder - 2.3.2 - client side image placeholders
-(c) 2012-2014 Ivan Malopinsky / http://imsky.co
-
-Provided under the MIT License.
-Commercial use requires attribution.
-
-*/
-var Holder = Holder || {};
-(function (app, win) {
-var system_config = {
- use_svg: false,
- use_canvas: false,
- use_fallback: false
-};
-var instance_config = {};
-var preempted = false;
-canvas = document.createElement('canvas');
-var dpr = 1, bsr = 1;
-var resizable_images = [];
-
-if (!canvas.getContext) {
- system_config.use_fallback = true;
-} else {
- if (canvas.toDataURL("image/png")
- .indexOf("data:image/png") < 0) {
- //Android doesn't support data URI
- system_config.use_fallback = true;
- } else {
- var ctx = canvas.getContext("2d");
- }
-}
-
-if(!!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect){
- system_config.use_svg = true;
- system_config.use_canvas = false;
-}
-
-if(!system_config.use_fallback){
- dpr = window.devicePixelRatio || 1,
- bsr = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1;
-}
-
-var ratio = dpr / bsr;
-
-var settings = {
- domain: "holder.js",
- images: "img",
- bgnodes: ".holderjs",
- themes: {
- "gray": {
- background: "#eee",
- foreground: "#aaa",
- size: 12
- },
- "social": {
- background: "#3a5a97",
- foreground: "#fff",
- size: 12
- },
- "industrial": {
- background: "#434A52",
- foreground: "#C2F200",
- size: 12
- },
- "sky": {
- background: "#0D8FDB",
- foreground: "#fff",
- size: 12
- },
- "vine": {
- background: "#39DBAC",
- foreground: "#1E292C",
- size: 12
- },
- "lava": {
- background: "#F8591A",
- foreground: "#1C2846",
- size: 12
- }
- },
- stylesheet: ""
-};
-app.flags = {
- dimensions: {
- regex: /^(\d+)x(\d+)$/,
- output: function (val) {
- var exec = this.regex.exec(val);
- return {
- width: +exec[1],
- height: +exec[2]
- }
- }
- },
- fluid: {
- regex: /^([0-9%]+)x([0-9%]+)$/,
- output: function (val) {
- var exec = this.regex.exec(val);
- return {
- width: exec[1],
- height: exec[2]
- }
- }
- },
- colors: {
- regex: /#([0-9a-f]{3,})\:#([0-9a-f]{3,})/i,
- output: function (val) {
- var exec = this.regex.exec(val);
- return {
- size: settings.themes.gray.size,
- foreground: "#" + exec[2],
- background: "#" + exec[1]
- }
- }
- },
- text: {
- regex: /text\:(.*)/,
- output: function (val) {
- return this.regex.exec(val)[1];
- }
- },
- font: {
- regex: /font\:(.*)/,
- output: function (val) {
- return this.regex.exec(val)[1];
- }
- },
- auto: {
- regex: /^auto$/
- },
- textmode: {
- regex: /textmode\:(.*)/,
- output: function(val){
- return this.regex.exec(val)[1];
- }
- }
-}
-
-function text_size(width, height, template) {
- height = parseInt(height, 10);
- width = parseInt(width, 10);
- var bigSide = Math.max(height, width)
- var smallSide = Math.min(height, width)
- var scale = 1 / 12;
- var newHeight = Math.min(smallSide * 0.75, 0.75 * bigSide * scale);
- return {
- height: Math.round(Math.max(template.size, newHeight))
- }
-}
-
-var svg_el = (function(){
- //Prevent IE <9 from initializing SVG renderer
- if(!window.XMLSerializer) return;
- var serializer = new XMLSerializer();
- var svg_ns = "http://www.w3.org/2000/svg"
- var svg = document.createElementNS(svg_ns, "svg");
- //IE throws an exception if this is set and Chrome requires it to be set
- if(svg.webkitMatchesSelector){
- svg.setAttribute("xmlns", "http://www.w3.org/2000/svg")
- }
- var bg_el = document.createElementNS(svg_ns, "rect")
- var text_el = document.createElementNS(svg_ns, "text")
- var textnode_el = document.createTextNode(null)
- text_el.setAttribute("text-anchor", "middle")
- text_el.appendChild(textnode_el)
- svg.appendChild(bg_el)
- svg.appendChild(text_el)
-
- return function(props){
- svg.setAttribute("width",props.width);
- svg.setAttribute("height", props.height);
- bg_el.setAttribute("width", props.width);
- bg_el.setAttribute("height", props.height);
- bg_el.setAttribute("fill", props.template.background);
- text_el.setAttribute("x", props.width/2)
- text_el.setAttribute("y", props.height/2)
- textnode_el.nodeValue=props.text
- text_el.setAttribute("style", css_properties({
- "fill": props.template.foreground,
- "font-weight": "bold",
- "font-size": props.text_height+"px",
- "font-family":props.font,
- "dominant-baseline":"central"
- }))
- return serializer.serializeToString(svg)
- }
-})()
-
-function css_properties(props){
- var ret = [];
- for(p in props){
- if(props.hasOwnProperty(p)){
- ret.push(p+":"+props[p])
- }
- }
- return ret.join(";")
-}
-
-function draw_canvas(args) {
- var ctx = args.ctx,
- dimensions = args.dimensions,
- template = args.template,
- ratio = args.ratio,
- holder = args.holder,
- literal = holder.textmode == "literal",
- exact = holder.textmode == "exact";
-
- var ts = text_size(dimensions.width, dimensions.height, template);
- var text_height = ts.height;
- var width = dimensions.width * ratio,
- height = dimensions.height * ratio;
- var font = template.font ? template.font : "Arial,Helvetica,sans-serif";
- canvas.width = width;
- canvas.height = height;
- ctx.textAlign = "center";
- ctx.textBaseline = "middle";
- ctx.fillStyle = template.background;
- ctx.fillRect(0, 0, width, height);
- ctx.fillStyle = template.foreground;
- ctx.font = "bold " + text_height + "px " + font;
- var text = template.text ? template.text : (Math.floor(dimensions.width) + "x" + Math.floor(dimensions.height));
- if (literal) {
- var dimensions = holder.dimensions;
- text = dimensions.width + "x" + dimensions.height;
- }
- else if(exact && holder.exact_dimensions){
- var dimensions = holder.exact_dimensions;
- text = (Math.floor(dimensions.width) + "x" + Math.floor(dimensions.height));
- }
- var text_width = ctx.measureText(text).width;
- if (text_width / width >= 0.75) {
- text_height = Math.floor(text_height * 0.75 * (width / text_width));
- }
- //Resetting font size if necessary
- ctx.font = "bold " + (text_height * ratio) + "px " + font;
- ctx.fillText(text, (width / 2), (height / 2), width);
- return canvas.toDataURL("image/png");
-}
-
-function draw_svg(args){
- var dimensions = args.dimensions,
- template = args.template,
- holder = args.holder,
- literal = holder.textmode == "literal",
- exact = holder.textmode == "exact";
-
- var ts = text_size(dimensions.width, dimensions.height, template);
- var text_height = ts.height;
- var width = dimensions.width,
- height = dimensions.height;
-
- var font = template.font ? template.font : "Arial,Helvetica,sans-serif";
- var text = template.text ? template.text : (Math.floor(dimensions.width) + "x" + Math.floor(dimensions.height));
-
- if (literal) {
- var dimensions = holder.dimensions;
- text = dimensions.width + "x" + dimensions.height;
- }
- else if(exact && holder.exact_dimensions){
- var dimensions = holder.exact_dimensions;
- text = (Math.floor(dimensions.width) + "x" + Math.floor(dimensions.height));
- }
- var string = svg_el({
- text: text,
- width:width,
- height:height,
- text_height:text_height,
- font:font,
- template:template
- })
- return "data:image/svg+xml;base64,"+btoa(unescape(encodeURIComponent(string)));
-}
-
-function draw(args) {
- if(instance_config.use_canvas && !instance_config.use_svg){
- return draw_canvas(args);
- }
- else{
- return draw_svg(args);
- }
-}
-
-function render(mode, el, holder, src) {
- var dimensions = holder.dimensions,
- theme = holder.theme,
- text = holder.text ? decodeURIComponent(holder.text) : holder.text;
- var dimensions_caption = dimensions.width + "x" + dimensions.height;
- theme = (text ? extend(theme, {
- text: text
- }) : theme);
- theme = (holder.font ? extend(theme, {
- font: holder.font
- }) : theme);
- el.setAttribute("data-src", src);
- holder.theme = theme;
- el.holder_data = holder;
-
- if (mode == "image") {
- el.setAttribute("alt", text ? text : theme.text ? theme.text + " [" + dimensions_caption + "]" : dimensions_caption);
- if (instance_config.use_fallback || !holder.auto) {
- el.style.width = dimensions.width + "px";
- el.style.height = dimensions.height + "px";
- }
- if (instance_config.use_fallback) {
- el.style.backgroundColor = theme.background;
- } else {
- el.setAttribute("src", draw({ctx: ctx, dimensions: dimensions, template: theme, ratio:ratio, holder: holder}));
-
- if(holder.textmode && holder.textmode == "exact"){
- resizable_images.push(el);
- resizable_update(el);
- }
-
- }
- } else if (mode == "background") {
- if (!instance_config.use_fallback) {
- el.style.backgroundImage = "url(" + draw({ctx:ctx, dimensions: dimensions, template: theme, ratio: ratio, holder: holder}) + ")";
- el.style.backgroundSize = dimensions.width + "px " + dimensions.height + "px";
- }
- } else if (mode == "fluid") {
- el.setAttribute("alt", text ? text : theme.text ? theme.text + " [" + dimensions_caption + "]" : dimensions_caption);
- if (dimensions.height.slice(-1) == "%") {
- el.style.height = dimensions.height
- } else if(holder.auto == null || !holder.auto){
- el.style.height = dimensions.height + "px"
- }
- if (dimensions.width.slice(-1) == "%") {
- el.style.width = dimensions.width
- } else if(holder.auto == null || !holder.auto){
- el.style.width = dimensions.width + "px"
- }
- if (el.style.display == "inline" || el.style.display === "" || el.style.display == "none") {
- el.style.display = "block";
- }
-
- set_initial_dimensions(el)
-
- if (instance_config.use_fallback) {
- el.style.backgroundColor = theme.background;
- } else {
- resizable_images.push(el);
- resizable_update(el);
- }
- }
-}
-
-function dimension_check(el, callback) {
- var dimensions = {
- height: el.clientHeight,
- width: el.clientWidth
- };
- if (!dimensions.height && !dimensions.width) {
- el.setAttribute("data-holder-invisible", true)
- callback.call(this, el)
- }
- else{
- el.removeAttribute("data-holder-invisible")
- return dimensions;
- }
-}
-
-function set_initial_dimensions(el){
- if(el.holder_data){
- var dimensions = dimension_check(el, app.invisible_error_fn( set_initial_dimensions))
- if(dimensions){
- var holder = el.holder_data;
- holder.initial_dimensions = dimensions;
- holder.fluid_data = {
- fluid_height: holder.dimensions.height.slice(-1) == "%",
- fluid_width: holder.dimensions.width.slice(-1) == "%",
- mode: null
- }
- if(holder.fluid_data.fluid_width && !holder.fluid_data.fluid_height){
- holder.fluid_data.mode = "width"
- holder.fluid_data.ratio = holder.initial_dimensions.width / parseFloat(holder.dimensions.height)
- }
- else if(!holder.fluid_data.fluid_width && holder.fluid_data.fluid_height){
- holder.fluid_data.mode = "height";
- holder.fluid_data.ratio = parseFloat(holder.dimensions.width) / holder.initial_dimensions.height
- }
- }
- }
-}
-
-function resizable_update(element) {
- var images;
- if (element.nodeType == null) {
- images = resizable_images;
- } else {
- images = [element]
- }
- for (var i in images) {
- if (!images.hasOwnProperty(i)) {
- continue;
- }
- var el = images[i]
- if (el.holder_data) {
- var holder = el.holder_data;
- var dimensions = dimension_check(el, app.invisible_error_fn( resizable_update))
- if(dimensions){
- if(holder.fluid){
- if(holder.auto){
- switch(holder.fluid_data.mode){
- case "width":
- dimensions.height = dimensions.width / holder.fluid_data.ratio;
- break;
- case "height":
- dimensions.width = dimensions.height * holder.fluid_data.ratio;
- break;
- }
- }
- el.setAttribute("src", draw({
- ctx: ctx,
- dimensions: dimensions,
- template: holder.theme,
- ratio: ratio,
- holder: holder
- }))
- }
- if(holder.textmode && holder.textmode == "exact"){
- holder.exact_dimensions = dimensions;
- el.setAttribute("src", draw({
- ctx: ctx,
- dimensions: holder.dimensions,
- template: holder.theme,
- ratio: ratio,
- holder: holder
- }))
- }
- }
- }
- }
-}
-
-function parse_flags(flags, options) {
- var ret = {
- theme: extend(settings.themes.gray, {})
- };
- var render = false;
- for (var fl = flags.length, j = 0; j < fl; j++) {
- var flag = flags[j];
- if (app.flags.dimensions.match(flag)) {
- render = true;
- ret.dimensions = app.flags.dimensions.output(flag);
- } else if (app.flags.fluid.match(flag)) {
- render = true;
- ret.dimensions = app.flags.fluid.output(flag);
- ret.fluid = true;
- } else if (app.flags.textmode.match(flag)) {
- ret.textmode = app.flags.textmode.output(flag)
- } else if (app.flags.colors.match(flag)) {
- ret.theme = app.flags.colors.output(flag);
- } else if (options.themes[flag]) {
- //If a theme is specified, it will override custom colors
- if(options.themes.hasOwnProperty(flag)){
- ret.theme = extend(options.themes[flag], {});
- }
- } else if (app.flags.font.match(flag)) {
- ret.font = app.flags.font.output(flag);
- } else if (app.flags.auto.match(flag)) {
- ret.auto = true;
- } else if (app.flags.text.match(flag)) {
- ret.text = app.flags.text.output(flag);
- }
- }
- return render ? ret : false;
-}
-
-for (var flag in app.flags) {
- if (!app.flags.hasOwnProperty(flag)) continue;
- app.flags[flag].match = function (val) {
- return val.match(this.regex)
- }
-}
-
-app.invisible_error_fn = function(fn){
- return function(el){
- if(el.hasAttribute("data-holder-invisible")){
- throw new Error("Holder: invisible placeholder")
- }
- }
-}
-
-app.add_theme = function (name, theme) {
- name != null && theme != null && (settings.themes[name] = theme);
- return app;
-};
-
-app.add_image = function (src, el) {
- var node = selector(el);
- if (node.length) {
- for (var i = 0, l = node.length; i < l; i++) {
- var img = document.createElement("img")
- img.setAttribute("data-src", src);
- node[i].appendChild(img);
- }
- }
- return app;
-};
-
-app.run = function (o) {
-
- instance_config = extend({}, system_config)
- preempted = true;
-
- var options = extend(settings, o),
- images = [],
- imageNodes = [],
- bgnodes = [];
-
- if(options.use_canvas != null && options.use_canvas){
- instance_config.use_canvas = true;
- instance_config.use_svg = false;
- }
-
- if (typeof (options.images) == "string") {
- imageNodes = selector(options.images);
- } else if (window.NodeList && options.images instanceof window.NodeList) {
- imageNodes = options.images;
- } else if (window.Node && options.images instanceof window.Node) {
- imageNodes = [options.images];
- } else if(window.HTMLCollection && options.images instanceof window.HTMLCollection){
- imageNodes = options.images
- }
-
- if (typeof (options.bgnodes) == "string") {
- bgnodes = selector(options.bgnodes);
- } else if (window.NodeList && options.elements instanceof window.NodeList) {
- bgnodes = options.bgnodes;
- } else if (window.Node && options.bgnodes instanceof window.Node) {
- bgnodes = [options.bgnodes];
- }
- for (i = 0, l = imageNodes.length; i < l; i++) images.push(imageNodes[i]);
-
- var holdercss = document.getElementById("holderjs-style");
- if (!holdercss) {
- holdercss = document.createElement("style");
- holdercss.setAttribute("id", "holderjs-style");
- holdercss.type = "text/css";
- document.getElementsByTagName("head")[0].appendChild(holdercss);
- }
-
- if (!options.nocss) {
- if (holdercss.styleSheet) {
- holdercss.styleSheet.cssText += options.stylesheet;
- } else {
- if(options.stylesheet.length){
- holdercss.appendChild(document.createTextNode(options.stylesheet));
- }
- }
- }
-
- var cssregex = new RegExp(options.domain + "\/(.*?)\"?\\)");
- for (var l = bgnodes.length, i = 0; i < l; i++) {
- var src = window.getComputedStyle(bgnodes[i], null)
- .getPropertyValue("background-image");
- var flags = src.match(cssregex);
- var bgsrc = bgnodes[i].getAttribute("data-background-src");
- if (flags) {
- var holder = parse_flags(flags[1].split("/"), options);
- if (holder) {
- render("background", bgnodes[i], holder, src);
- }
- } else if (bgsrc != null) {
- var holder = parse_flags(bgsrc.substr(bgsrc.lastIndexOf(options.domain) + options.domain.length + 1)
- .split("/"), options);
- if (holder) {
- render("background", bgnodes[i], holder, src);
- }
- }
- }
- for (l = images.length, i = 0; i < l; i++) {
- var attr_data_src, attr_src;
- attr_src = attr_data_src = src = null;
- try {
- attr_src = images[i].getAttribute("src");
- attr_datasrc = images[i].getAttribute("data-src");
- } catch (e) {}
- if (attr_datasrc == null && !! attr_src && attr_src.indexOf(options.domain) >= 0) {
- src = attr_src;
- } else if ( !! attr_datasrc && attr_datasrc.indexOf(options.domain) >= 0) {
- src = attr_datasrc;
- }
- if (src) {
- var holder = parse_flags(src.substr(src.lastIndexOf(options.domain) + options.domain.length + 1).split("/"), options);
- if (holder) {
- if (holder.fluid) {
- render("fluid", images[i], holder, src)
- } else {
- render("image", images[i], holder, src);
- }
- }
- }
- }
- return app;
-};
-
-contentLoaded(win, function () {
- if (window.addEventListener) {
- window.addEventListener("resize", resizable_update, false);
- window.addEventListener("orientationchange", resizable_update, false);
- } else {
- window.attachEvent("onresize", resizable_update)
- }
- preempted || app.run({});
-
- if (typeof window.Turbolinks === "object") {
- document.addEventListener("page:change", function() { app.run({}) })
- }
-});
-if (typeof define === "function" && define.amd) {
- define([], function () {
- return app;
- });
-}
-
-//github.com/davidchambers/Base64.js
-(function(){function t(t){this.message=t}var e="undefined"!=typeof exports?exports:this,r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";t.prototype=Error(),t.prototype.name="InvalidCharacterError",e.btoa||(e.btoa=function(e){for(var o,n,a=0,i=r,c="";e.charAt(0|a)||(i="=",a%1);c+=i.charAt(63&o>>8-8*(a%1))){if(n=e.charCodeAt(a+=.75),n>255)throw new t("'btoa' failed");o=o<<8|n}return c}),e.atob||(e.atob=function(e){if(e=e.replace(/=+$/,""),1==e.length%4)throw new t("'atob' failed");for(var o,n,a=0,i=0,c="";n=e.charAt(i++);~n&&(o=a%4?64*o+n:n,a++%4)?c+=String.fromCharCode(255&o>>(6&-2*a)):0)n=r.indexOf(n);return c})})();
-
-//getElementsByClassName polyfill
-document.getElementsByClassName||(document.getElementsByClassName=function(e){var t=document,n,r,i,s=[];if(t.querySelectorAll)return t.querySelectorAll("."+e);if(t.evaluate){r=".//*[contains(concat(' ', @class, ' '), ' "+e+" ')]",n=t.evaluate(r,t,null,0,null);while(i=n.iterateNext())s.push(i)}else{n=t.getElementsByTagName("*"),r=new RegExp("(^|\\s)"+e+"(\\s|$)");for(i=0;iupdateCollapse."),
+ actionButton("p1Button", "Push Me!"),
+ selectInput("styleSelect", "Select style for Panel 1",
+ c("default", "primary", "danger", "warning", "info", "success"))
+ ),
+ mainPanel(
+ bsCollapse(id = "collapseExample", open = "Panel 2",
+ bsCollapsePanel("Panel 1", "This is a panel with just text ",
+ "and has the default style. You can change the style in ",
+ "the sidebar.", style = "info"),
+ bsCollapsePanel("Panel 2", "This panel has a generic plot. ",
+ "and a 'success' style.", plotOutput("genericPlot"), style = "success")
+ ),
+
+ uiOutput("tooltip_test"),
+ actionButton("test2", "Test2"),
+ bsTooltip("test2", title = "Test2", placement="right"),
+ tipify(tags$button("Hello"), "Test without ID")
+
+ )
+ )
+ ),
+ server =
+ function(input, output, session) {
+ output$genericPlot <- renderPlot(plot(rnorm(100)))
+ observeEvent(input$p1Button, ({
+ updateCollapse(session, "collapseExample", open = "Panel 1")
+ }))
+ observeEvent(input$styleSelect, ({
+ updateCollapse(session, "collapseExample", style = list("Panel 1" = input$styleSelect))
+ }))
+
+ output$tooltip_test <- renderUI({
+ tipify(actionButton("test", "Test"), title = "test", placement = "right")
+ })
+ }
+)
+
+runApp(app)
\ No newline at end of file
diff --git a/inst/www/bootstrap3-typeahead.js b/inst/www/bootstrap3-typeahead.js
new file mode 100644
index 0000000..d824f6d
--- /dev/null
+++ b/inst/www/bootstrap3-typeahead.js
@@ -0,0 +1,476 @@
+/* =============================================================
+ * bootstrap3-typeahead.js v3.1.0
+ * https://github.com/bassjobsen/Bootstrap-3-Typeahead
+ * =============================================================
+ * Original written by @mdo and @fat
+ * =============================================================
+ * Copyright 2014 Bass Jobsen @bassjobsen
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============================================================ */
+
+
+(function (root, factory) {
+
+ 'use strict';
+
+ // CommonJS module is defined
+ if (typeof module !== 'undefined' && module.exports) {
+ module.exports = factory(require('jquery'));
+ }
+ // AMD module is defined
+ else if (typeof define === 'function' && define.amd) {
+ define(['jquery'], function ($) {
+ return factory ($);
+ });
+ } else {
+ factory(root.jQuery);
+ }
+
+}(this, function ($) {
+
+ 'use strict';
+ // jshint laxcomma: true
+
+
+ /* TYPEAHEAD PUBLIC CLASS DEFINITION
+ * ================================= */
+
+ var Typeahead = function (element, options) {
+ this.$element = $(element);
+ this.options = $.extend({}, $.fn.typeahead.defaults, options);
+ this.matcher = this.options.matcher || this.matcher;
+ this.sorter = this.options.sorter || this.sorter;
+ this.select = this.options.select || this.select;
+ this.autoSelect = typeof this.options.autoSelect == 'boolean' ? this.options.autoSelect : true;
+ this.highlighter = this.options.highlighter || this.highlighter;
+ this.render = this.options.render || this.render;
+ this.updater = this.options.updater || this.updater;
+ this.displayText = this.options.displayText || this.displayText;
+ this.source = this.options.source;
+ this.delay = this.options.delay;
+ this.$menu = $(this.options.menu);
+ this.$appendTo = this.options.appendTo ? $(this.options.appendTo) : null;
+ this.shown = false;
+ this.listen();
+ this.showHintOnFocus = typeof this.options.showHintOnFocus == 'boolean' ? this.options.showHintOnFocus : false;
+ this.afterSelect = this.options.afterSelect;
+ this.addItem = false;
+ };
+
+ Typeahead.prototype = {
+
+ constructor: Typeahead,
+
+ select: function () {
+ var val = this.$menu.find('.active').data('value');
+ this.$element.data('active', val);
+ if(this.autoSelect || val) {
+ var newVal = this.updater(val);
+ this.$element
+ .val(this.displayText(newVal) || newVal)
+ .change();
+ this.afterSelect(newVal);
+ }
+ return this.hide();
+ },
+
+ updater: function (item) {
+ return item;
+ },
+
+ setSource: function (source) {
+ this.source = source;
+ },
+
+ show: function () {
+ var pos = $.extend({}, this.$element.position(), {
+ height: this.$element[0].offsetHeight
+ }), scrollHeight;
+
+ scrollHeight = typeof this.options.scrollHeight == 'function' ?
+ this.options.scrollHeight.call() :
+ this.options.scrollHeight;
+
+ (this.$appendTo ? this.$menu.appendTo(this.$appendTo) : this.$menu.insertAfter(this.$element))
+ .css({
+ top: pos.top + pos.height + scrollHeight
+ , left: pos.left
+ })
+ .show();
+
+ this.shown = true;
+ return this;
+ },
+
+ hide: function () {
+ this.$menu.hide();
+ this.shown = false;
+ return this;
+ },
+
+ lookup: function (query) {
+ var items;
+ if (typeof(query) != 'undefined' && query !== null) {
+ this.query = query;
+ } else {
+ this.query = this.$element.val() || '';
+ }
+
+ if (this.query.length < this.options.minLength) {
+ return this.shown ? this.hide() : this;
+ }
+
+ var worker = $.proxy(function() {
+
+ if($.isFunction(this.source)) this.source(this.query, $.proxy(this.process, this));
+ else if (this.source) {
+ this.process(this.source);
+ }
+ }, this);
+
+ clearTimeout(this.lookupWorker);
+ this.lookupWorker = setTimeout(worker, this.delay);
+ },
+
+ process: function (items) {
+ var that = this;
+
+ items = $.grep(items, function (item) {
+ return that.matcher(item);
+ });
+
+ items = this.sorter(items);
+
+ if (!items.length && !this.options.addItem) {
+ return this.shown ? this.hide() : this;
+ }
+
+ if (items.length > 0) {
+ this.$element.data('active', items[0]);
+ } else {
+ this.$element.data('active', null);
+ }
+
+ // Add item
+ if (this.options.addItem){
+ items.push(this.options.addItem);
+ }
+
+ if (this.options.items == 'all') {
+ return this.render(items).show();
+ } else {
+ return this.render(items.slice(0, this.options.items)).show();
+ }
+ },
+
+ matcher: function (item) {
+ var it = this.displayText(item);
+ return ~it.toLowerCase().indexOf(this.query.toLowerCase());
+ },
+
+ sorter: function (items) {
+ var beginswith = []
+ , caseSensitive = []
+ , caseInsensitive = []
+ , item;
+
+ while ((item = items.shift())) {
+ var it = this.displayText(item);
+ if (!it.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item);
+ else if (~it.indexOf(this.query)) caseSensitive.push(item);
+ else caseInsensitive.push(item);
+ }
+
+ return beginswith.concat(caseSensitive, caseInsensitive);
+ },
+
+ highlighter: function (item) {
+ var html = $('');
+ var query = this.query;
+ var i = item.toLowerCase().indexOf(query.toLowerCase());
+ var len, leftPart, middlePart, rightPart, strong;
+ len = query.length;
+ if(len === 0){
+ return html.text(item).html();
+ }
+ while (i > -1) {
+ leftPart = item.substr(0, i);
+ middlePart = item.substr(i, len);
+ rightPart = item.substr(i + len);
+ strong = $('').text(middlePart);
+ html
+ .append(document.createTextNode(leftPart))
+ .append(strong);
+ item = rightPart;
+ i = item.toLowerCase().indexOf(query.toLowerCase());
+ }
+ return html.append(document.createTextNode(item)).html();
+ },
+
+ render: function (items) {
+ var that = this;
+ var self = this;
+ var activeFound = false;
+ items = $(items).map(function (i, item) {
+ var text = self.displayText(item);
+ i = $(that.options.item).data('value', item);
+ i.find('a').html(that.highlighter(text));
+ if (text == self.$element.val()) {
+ i.addClass('active');
+ self.$element.data('active', item);
+ activeFound = true;
+ }
+ return i[0];
+ });
+
+ if (this.autoSelect && !activeFound) {
+ items.first().addClass('active');
+ this.$element.data('active', items.first().data('value'));
+ }
+ this.$menu.html(items);
+ return this;
+ },
+
+ displayText: function(item) {
+ return item.name || item;
+ },
+
+ next: function (event) {
+ var active = this.$menu.find('.active').removeClass('active')
+ , next = active.next();
+
+ if (!next.length) {
+ next = $(this.$menu.find('li')[0]);
+ }
+
+ next.addClass('active');
+ },
+
+ prev: function (event) {
+ var active = this.$menu.find('.active').removeClass('active')
+ , prev = active.prev();
+
+ if (!prev.length) {
+ prev = this.$menu.find('li').last();
+ }
+
+ prev.addClass('active');
+ },
+
+ listen: function () {
+ this.$element
+ .on('focus', $.proxy(this.focus, this))
+ .on('blur', $.proxy(this.blur, this))
+ .on('keypress', $.proxy(this.keypress, this))
+ .on('keyup', $.proxy(this.keyup, this));
+
+ if (this.eventSupported('keydown')) {
+ this.$element.on('keydown', $.proxy(this.keydown, this));
+ }
+
+ this.$menu
+ .on('click', $.proxy(this.click, this))
+ .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
+ .on('mouseleave', 'li', $.proxy(this.mouseleave, this));
+ },
+
+ destroy : function () {
+ this.$element.data('typeahead',null);
+ this.$element.data('active',null);
+ this.$element
+ .off('focus')
+ .off('blur')
+ .off('keypress')
+ .off('keyup');
+
+ if (this.eventSupported('keydown')) {
+ this.$element.off('keydown');
+ }
+
+ this.$menu.remove();
+ },
+
+ eventSupported: function(eventName) {
+ var isSupported = eventName in this.$element;
+ if (!isSupported) {
+ this.$element.setAttribute(eventName, 'return;');
+ isSupported = typeof this.$element[eventName] === 'function';
+ }
+ return isSupported;
+ },
+
+ move: function (e) {
+ if (!this.shown) return;
+
+ switch(e.keyCode) {
+ case 9: // tab
+ case 13: // enter
+ case 27: // escape
+ e.preventDefault();
+ break;
+
+ case 38: // up arrow
+ // with the shiftKey (this is actually the left parenthesis)
+ if (e.shiftKey) return;
+ e.preventDefault();
+ this.prev();
+ break;
+
+ case 40: // down arrow
+ // with the shiftKey (this is actually the right parenthesis)
+ if (e.shiftKey) return;
+ e.preventDefault();
+ this.next();
+ break;
+ }
+
+ e.stopPropagation();
+ },
+
+ keydown: function (e) {
+ this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27]);
+ if (!this.shown && e.keyCode == 40) {
+ this.lookup();
+ } else {
+ this.move(e);
+ }
+ },
+
+ keypress: function (e) {
+ if (this.suppressKeyPressRepeat) return;
+ this.move(e);
+ },
+
+ keyup: function (e) {
+ switch(e.keyCode) {
+ case 40: // down arrow
+ case 38: // up arrow
+ case 16: // shift
+ case 17: // ctrl
+ case 18: // alt
+ break;
+
+ case 9: // tab
+ case 13: // enter
+ if (!this.shown) return;
+ this.select();
+ break;
+
+ case 27: // escape
+ if (!this.shown) return;
+ this.hide();
+ break;
+ default:
+ this.lookup();
+ }
+
+ e.stopPropagation();
+ e.preventDefault();
+ },
+
+ focus: function (e) {
+ if (!this.focused) {
+ this.focused = true;
+ if (this.options.showHintOnFocus) {
+ this.lookup('');
+ }
+ }
+ },
+
+ blur: function (e) {
+ this.focused = false;
+ if (!this.mousedover && this.shown) this.hide();
+ },
+
+ click: function (e) {
+ e.stopPropagation();
+ e.preventDefault();
+ this.select();
+ this.$element.focus();
+ },
+
+ mouseenter: function (e) {
+ this.mousedover = true;
+ this.$menu.find('.active').removeClass('active');
+ $(e.currentTarget).addClass('active');
+ },
+
+ mouseleave: function (e) {
+ this.mousedover = false;
+ if (!this.focused && this.shown) this.hide();
+ }
+
+ };
+
+
+ /* TYPEAHEAD PLUGIN DEFINITION
+ * =========================== */
+
+ var old = $.fn.typeahead;
+
+ $.fn.typeahead = function (option) {
+ var arg = arguments;
+ if (typeof option == 'string' && option == 'getActive') {
+ return this.data('active');
+ }
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('typeahead')
+ , options = typeof option == 'object' && option;
+ if (!data) $this.data('typeahead', (data = new Typeahead(this, options)));
+ if (typeof option == 'string') {
+ if (arg.length > 1) {
+ data[option].apply(data, Array.prototype.slice.call(arg ,1));
+ } else {
+ data[option]();
+ }
+ }
+ });
+ };
+
+ $.fn.typeahead.defaults = {
+ source: []
+ , items: 8
+ , menu: '