Merge pull request #411 from yihui/selectize/backspace

Selectize backspace issue
This commit is contained in:
Joe Cheng
2014-03-05 00:29:44 -08:00
6 changed files with 69 additions and 18 deletions

4
NEWS
View File

@@ -13,6 +13,10 @@ shiny 0.8.0.99
selectize.js (https://github.com/brianreavis/selectize.js), which extends
the basic select input in many aspects.
* The `selectInput()` function also gained a new argument `selectize = TRUE`
to makes use of selectize.js by default. If you want to revert back to the
original select input, you have to call selectInput(..., selectize = FALSE).
* Upgraded to Bootstrap 2.3.2 and jQuery 1.11.0.
* Make `tags$head()` and `singleton()` behave correctly when used with

View File

@@ -686,6 +686,7 @@ choicesWithNames <- function(choices) {
#' \code{multiple = TRUE}). If not specified then defaults to the first value
#' for single-select lists and no values for multiple select lists.
#' @param multiple Is selection of multiple items allowed?
#' @param selectize Whether to use \pkg{selectize.js} or not.
#' @return A select list control that can be added to a UI definition.
#'
#' @family input elements
@@ -697,11 +698,8 @@ choicesWithNames <- function(choices) {
#' "Transmission" = "am",
#' "Gears" = "gear"))
#' @export
selectInput <- function(inputId,
label,
choices,
selected = NULL,
multiple = FALSE) {
selectInput <- function(inputId, label, choices, selected = NULL,
multiple = FALSE, selectize = TRUE) {
# resolve names
choices <- choicesWithNames(choices)
@@ -731,21 +729,36 @@ selectInput <- function(inputId,
selectTag <- tagSetChildren(selectTag, list = optionTags)
# return label and select tag
tagList(controlLabel(inputId, label), selectTag)
res <- tagList(controlLabel(inputId, label), selectTag)
if (!selectize) return(res)
selectizeIt(inputId, res, NULL, nonempty = !multiple && !("" %in% choices))
}
#' @rdname selectInput
#' @param ... arguments passed to \code{selectInput()}
#' @param options a list of options; see the documentation of \pkg{selectize.js}
#' @param ... Arguments passed to \code{selectInput()}.
#' @param options A list of options. See the documentation of \pkg{selectize.js}
#' for possible options (character option values inside \code{\link{I}()} will
#' be treated as literal JavaScript code; see \code{\link{renderDataTable}()}
#' for details)
#' for details).
#' @note The selectize input created from \code{selectizeInput()} allows
#' deletion of the selected option even in a single select input, which will
#' return an empty string as its value. This is the default behavior of
#' \pkg{selectize.js}. However, the selectize input created from
#' \code{selectInput(..., selectize = TRUE)} will ignore the empty string
#' value when it is a single choice input and the empty string is not in the
#' \code{choices} argument. This is to keep compatibility with
#' \code{selectInput(..., selectize = FALSE)}.
#' @export
selectizeInput <- function(inputId, ..., options = NULL) {
selectizeIt(inputId, selectInput(inputId, ..., selectize = FALSE), options)
}
# given a select input and its id, selectize it
selectizeIt <- function(inputId, select, options, nonempty = FALSE) {
res <- checkAsIs(options)
tagList(
selectInput(inputId, ...),
select,
singleton(tags$head(
tags$link(rel = 'stylesheet', type = 'text/css',
href = 'shared/selectize/css/selectize.bootstrap2.css'),
@@ -755,7 +768,8 @@ selectizeInput <- function(inputId, ..., options = NULL) {
tags$script(src = 'shared/selectize/js/selectize.min.js')
)),
tags$script(
type = 'application/json', `data-for` = inputId,
type = 'application/json',
`data-for` = inputId, `data-nonempty` = if (nonempty) '',
`data-eval` = if (length(res$eval)) HTML(toJSON(res$eval)),
if (length(res$options)) HTML(toJSON(res$options)) else '{}'
)

View File

@@ -7,7 +7,7 @@ test_that("CSS unit validation", {
}
# Test strings and expected results
strings <- c("100x", "10px", "10.4px", ".4px", "1px0", "px", "5", "%", "5%", "auto", "1auto", "")
strings <- c("100x", "10px", "10.4px", ".4px", "1px0", "px", "5", "%", "5%", "auto", "1auto", "")
expected <- c(NA, "10px", "10.4px", ".4px", NA, NA, NA, NA, "5%", "auto", NA, NA)
results <- vapply(strings, validateCssUnit_wrap, character(1), USE.NAMES = FALSE)
expect_equal(results, expected)
@@ -22,7 +22,7 @@ test_that("Repeated names for selectInput and radioButtons choices", {
# tag object, but they get the job done for now.
# Select input
x <- selectInput('id','label', choices = c(a='x1', a='x2', b='x3'))
x <- selectInput('id','label', choices = c(a='x1', a='x2', b='x3'), selectize = FALSE)
choices <- x[[2]]$children
expect_equal(choices[[1]]$children[[1]], 'a')

View File

@@ -85,7 +85,7 @@ span.jslider {
.crosshair {
cursor: crosshair;
}
}
.well input[type="text"],
.well input[type="number"],
@@ -97,3 +97,8 @@ span.jslider {
.qt pre, .qt code {
font-family: monospace !important;
}
/* consistency with bootstrap.css for selectize.js */
.selectize-control {
margin-bottom: 10px;
}

View File

@@ -2041,6 +2041,20 @@
valueField: 'value',
searchField: ['label']
}, JSON.parse(config.html()));
if (config.data('nonempty') !== undefined) {
options = $.extend(options, {
onItemRemove: function(value) {
if (this.getValue() === "")
$("select[id=" + el.id + "]").empty().append($("<option/>", {
"value": value, "selected": true
})).trigger("change");
},
onDropdownClose: function($dropdown) {
if (this.getValue() === "")
this.setValue($("select[id=" + el.id + "]").val());
}
});
}
// options that should be eval()ed
if (config.data('eval') instanceof Array)
$.each(config.data('eval'), function(i, x) {

View File

@@ -4,7 +4,8 @@
\alias{selectizeInput}
\title{Create a select list input control}
\usage{
selectInput(inputId, label, choices, selected = NULL, multiple = FALSE)
selectInput(inputId, label, choices, selected = NULL, multiple = FALSE,
selectize = TRUE)
selectizeInput(inputId, ..., options = NULL)
}
@@ -25,13 +26,16 @@ selectizeInput(inputId, ..., options = NULL)
\item{multiple}{Is selection of multiple items allowed?}
\item{...}{arguments passed to \code{selectInput()}}
\item{selectize}{Whether to use \pkg{selectize.js} or
not.}
\item{options}{a list of options; see the documentation
\item{...}{Arguments passed to \code{selectInput()}.}
\item{options}{A list of options. See the documentation
of \pkg{selectize.js} for possible options (character
option values inside \code{\link{I}()} will be treated as
literal JavaScript code; see
\code{\link{renderDataTable}()} for details)}
\code{\link{renderDataTable}()} for details).}
}
\value{
A select list control that can be added to a UI definition.
@@ -45,6 +49,16 @@ multiple items from a list of values.
(\url{https://github.com/brianreavis/selectize.js}) to extend the basic
select input element.
}
\note{
The selectize input created from \code{selectizeInput()} allows
deletion of the selected option even in a single select input, which will
return an empty string as its value. This is the default behavior of
\pkg{selectize.js}. However, the selectize input created from
\code{selectInput(..., selectize = TRUE)} will ignore the empty string
value when it is a single choice input and the empty string is not in the
\code{choices} argument. This is to keep compatibility with
\code{selectInput(..., selectize = FALSE)}.
}
\examples{
selectInput("variable", "Variable:",
c("Cylinders" = "cyl",