Compare commits

...

2 Commits

Author SHA1 Message Date
Joe Cheng
5ce8272a29 Fix unit tests
For some reason, having two class attributes reorders the
order of the class vs id attributes
2020-08-06 12:57:15 -07:00
Joe Cheng
e722efd2d9 Allow opting out of binding generic inputs
Fixes #2956
2020-08-06 00:15:25 -07:00
20 changed files with 105 additions and 33 deletions

View File

@@ -31,7 +31,7 @@ checkboxInput <- function(inputId, label, value = FALSE, width = NULL) {
value <- restoreInput(id = inputId, default = value)
inputTag <- tags$input(id = inputId, type="checkbox")
inputTag <- tags$input(id = inputId, type="checkbox", class = "shiny-input-checkbox")
if (!is.null(value) && value)
inputTag$attribs$checked <- "checked"

View File

@@ -89,6 +89,7 @@ fileInput <- function(inputId, label, multiple = FALSE, accept = NULL,
inputTag <- tags$input(
id = inputId,
class = "shiny-input-file",
name = inputId,
type = "file",
# Don't use "display: none;" style, which causes keyboard accessibility issue; instead use the following workaround: https://css-tricks.com/places-its-tempting-to-use-display-none-but-dont/

View File

@@ -35,7 +35,7 @@ numericInput <- function(inputId, label, value, min = NA, max = NA, step = NA,
value <- restoreInput(id = inputId, default = value)
# build input tag
inputTag <- tags$input(id = inputId, type = "number", class="form-control",
inputTag <- tags$input(id = inputId, type = "number", class="form-control shiny-input-number",
value = formatNoSci(value))
if (!is.na(min))
inputTag$attribs$min = min

View File

@@ -35,7 +35,7 @@ passwordInput <- function(inputId, label, value = "", width = NULL,
div(class = "form-group shiny-input-container",
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
shinyInputLabel(inputId, label),
tags$input(id = inputId, type="password", class="form-control", value=value,
tags$input(id = inputId, type="password", class="shiny-input-password form-control", value=value,
placeholder = placeholder)
)
}

View File

@@ -98,6 +98,7 @@ selectInput <- function(inputId, label, choices, selected = NULL,
# create select tag and add options
selectTag <- tags$select(
id = inputId,
class = "shiny-input-select",
class = if (!selectize) "form-control",
size = size,
selectOptions(choices, selected)

View File

@@ -42,7 +42,7 @@ textInput <- function(inputId, label, value = "", width = NULL,
div(class = "form-group shiny-input-container",
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
shinyInputLabel(inputId, label),
tags$input(id = inputId, type="text", class="form-control", value=value,
tags$input(id = inputId, type="text", class="shiny-input-text form-control", value=value,
placeholder = placeholder)
)
}

View File

@@ -64,7 +64,7 @@ textAreaInput <- function(inputId, label, value = "", width = NULL, height = NUL
shinyInputLabel(inputId, label),
tags$textarea(
id = inputId,
class = "form-control",
class = "shiny-input-textarea form-control",
placeholder = placeholder,
style = style,
rows = rows,

View File

@@ -11,6 +11,13 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
var exports = window.Shiny = window.Shiny || {};
exports.version = "1.5.0.9001"; // Version number inserted by Grunt
if (!exports.hasOwnProperty("bindGenericInputs")) {
// Setting Shiny.bindGenericInputs=false during page load prevents inputs
// that don't have Shiny-specific classnames from being bound. See
// https://github.com/rstudio/shiny/issues/2956 for context.
exports.bindGenericInputs = true;
}
var origPushState = window.history.pushState;
window.history.pushState = function () {
@@ -4252,12 +4259,16 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
var textInputBinding = new InputBinding();
$.extend(textInputBinding, {
find: function find(scope) {
var $inputs = $(scope).find('input[type="text"], input[type="search"], input[type="url"], input[type="email"]'); // selectize.js 0.12.4 inserts a hidden text input with an
// id that ends in '-selectized'. The .not() selector below
// is to prevent textInputBinding from accidentally picking up
// this hidden element as a shiny input (#2396)
if (exports.bindGenericInputs) {
var $inputs = $(scope).find('input[type="text"], input[type="search"], input[type="url"], input[type="email"]'); // selectize.js 0.12.4 inserts a hidden text input with an
// id that ends in '-selectized'. The .not() selector below
// is to prevent textInputBinding from accidentally picking up
// this hidden element as a shiny input (#2396)
return $inputs.not('input[type="text"][id$="-selectized"]');
return $inputs.not('input[type="text"][id$="-selectized"]');
} else {
return $(scope).find('input.shiny-input-text');
}
},
getId: function getId(el) {
return InputBinding.prototype.getId.call(this, el) || el.name;
@@ -4308,7 +4319,11 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
var textareaInputBinding = {};
$.extend(textareaInputBinding, textInputBinding, {
find: function find(scope) {
return $(scope).find('textarea');
if (exports.bindGenericInputs) {
return $(scope).find('textarea');
} else {
return $(scope).find('textarea.shiny-input-textarea');
}
}
});
inputBindings.register(textareaInputBinding, 'shiny.textareaInput'); //---------------------------------------------------------------------
@@ -4317,7 +4332,11 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
var passwordInputBinding = {};
$.extend(passwordInputBinding, textInputBinding, {
find: function find(scope) {
return $(scope).find('input[type="password"]');
if (exports.bindGenericInputs) {
return $(scope).find('input[type="password"]');
} else {
return $(scope).find('input[type="password"].shiny-input-password');
}
},
getType: function getType(el) {
return "shiny.password";
@@ -4329,7 +4348,11 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
var numberInputBinding = {};
$.extend(numberInputBinding, textInputBinding, {
find: function find(scope) {
return $(scope).find('input[type="number"]');
if (exports.bindGenericInputs) {
return $(scope).find('input[type="number"]');
} else {
return $(scope).find('input[type="number"].shiny-input-number');
}
},
getValue: function getValue(el) {
var numberVal = $(el).val();
@@ -4370,7 +4393,11 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
var checkboxInputBinding = new InputBinding();
$.extend(checkboxInputBinding, {
find: function find(scope) {
return $(scope).find('input[type="checkbox"]');
if (exports.bindGenericInputs) {
return $(scope).find('input[type="checkbox"]');
} else {
return $(scope).find('input[type="checkbox"].shiny-input-checkbox');
}
},
getValue: function getValue(el) {
return el.checked;
@@ -5044,7 +5071,11 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
var selectInputBinding = new InputBinding();
$.extend(selectInputBinding, {
find: function find(scope) {
return $(scope).find('select');
if (exports.bindGenericInputs) {
return $(scope).find('select');
} else {
return $(scope).find('select.shiny-input-select');
}
},
getType: function getType(el) {
var $el = $(el);
@@ -5820,7 +5851,11 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
var fileInputBinding = new InputBinding();
$.extend(fileInputBinding, {
find: function find(scope) {
return $(scope).find('input[type="file"]');
if (exports.bindGenericInputs) {
return $(scope).find('input[type="file"]');
} else {
return $(scope).find('input[type="file"].shiny-input-file');
}
},
getId: function getId(el) {
return InputBinding.prototype.getId.call(this, el) || el.name;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -5,6 +5,13 @@
exports.version = "{{ VERSION }}"; // Version number inserted by Grunt
if (!exports.hasOwnProperty("bindGenericInputs")) {
// Setting Shiny.bindGenericInputs=false during page load prevents inputs
// that don't have Shiny-specific classnames from being bound. See
// https://github.com/rstudio/shiny/issues/2956 for context.
exports.bindGenericInputs = true;
}
var origPushState = window.history.pushState;
window.history.pushState = function() {
var result = origPushState.apply(this, arguments);

View File

@@ -1,7 +1,11 @@
var checkboxInputBinding = new InputBinding();
$.extend(checkboxInputBinding, {
find: function(scope) {
return $(scope).find('input[type="checkbox"]');
if (exports.bindGenericInputs) {
return $(scope).find('input[type="checkbox"]');
} else {
return $(scope).find('input[type="checkbox"].shiny-input-checkbox');
}
},
getValue: function(el) {
return el.checked;

View File

@@ -267,7 +267,11 @@ var $fileInputs = $();
var fileInputBinding = new InputBinding();
$.extend(fileInputBinding, {
find: function(scope) {
return $(scope).find('input[type="file"]');
if (exports.bindGenericInputs) {
return $(scope).find('input[type="file"]');
} else {
return $(scope).find('input[type="file"].shiny-input-file');
}
},
getId: function(el) {
return InputBinding.prototype.getId.call(this, el) || el.name;

View File

@@ -1,7 +1,11 @@
var numberInputBinding = {};
$.extend(numberInputBinding, textInputBinding, {
find: function(scope) {
return $(scope).find('input[type="number"]');
if (exports.bindGenericInputs) {
return $(scope).find('input[type="number"]');
} else {
return $(scope).find('input[type="number"].shiny-input-number');
}
},
getValue: function(el) {
var numberVal = $(el).val();

View File

@@ -1,7 +1,11 @@
var passwordInputBinding = {};
$.extend(passwordInputBinding, textInputBinding, {
find: function(scope) {
return $(scope).find('input[type="password"]');
if (exports.bindGenericInputs) {
return $(scope).find('input[type="password"]');
} else {
return $(scope).find('input[type="password"].shiny-input-password');
}
},
getType: function(el) {
return "shiny.password";

View File

@@ -1,7 +1,11 @@
var selectInputBinding = new InputBinding();
$.extend(selectInputBinding, {
find: function(scope) {
return $(scope).find('select');
if (exports.bindGenericInputs) {
return $(scope).find('select');
} else {
return $(scope).find('select.shiny-input-select');
}
},
getType: function(el) {
var $el = $(el);

View File

@@ -1,12 +1,16 @@
var textInputBinding = new InputBinding();
$.extend(textInputBinding, {
find: function(scope) {
var $inputs = $(scope).find('input[type="text"], input[type="search"], input[type="url"], input[type="email"]');
// selectize.js 0.12.4 inserts a hidden text input with an
// id that ends in '-selectized'. The .not() selector below
// is to prevent textInputBinding from accidentally picking up
// this hidden element as a shiny input (#2396)
return $inputs.not('input[type="text"][id$="-selectized"]');
if (exports.bindGenericInputs) {
var $inputs = $(scope).find('input[type="text"], input[type="search"], input[type="url"], input[type="email"]');
// selectize.js 0.12.4 inserts a hidden text input with an
// id that ends in '-selectized'. The .not() selector below
// is to prevent textInputBinding from accidentally picking up
// this hidden element as a shiny input (#2396)
return $inputs.not('input[type="text"][id$="-selectized"]');
} else {
return $(scope).find('input.shiny-input-text');
}
},
getId: function(el) {
return InputBinding.prototype.getId.call(this, el) || el.name;

View File

@@ -1,7 +1,11 @@
var textareaInputBinding = {};
$.extend(textareaInputBinding, textInputBinding, {
find: function(scope) {
return $(scope).find('textarea');
if (exports.bindGenericInputs) {
return $(scope).find('textarea');
} else {
return $(scope).find('textarea.shiny-input-textarea');
}
}
});
inputBindings.register(textareaInputBinding, 'shiny.textareaInput');

View File

@@ -24,7 +24,7 @@ test_that("Repeated names for selectInput and radioButtons choices", {
# Select input
x <- selectInput('id','label', choices = c(a='x1', a='x2', b='x3'), selectize = FALSE)
expect_true(grepl(fixed = TRUE,
'<select id="id" class="form-control"><option value="x1" selected>a</option>\n<option value="x2">a</option>\n<option value="x3">b</option></select>',
'<select class="shiny-input-select form-control" id="id"><option value="x1" selected>a</option>\n<option value="x2">a</option>\n<option value="x3">b</option></select>',
format(x)
))
@@ -251,7 +251,7 @@ test_that("selectInput selects items by default", {
# Nothing selected when choices=NULL
expect_true(grepl(fixed = TRUE,
'<select id="x" class="form-control"></select>',
'<select class="shiny-input-select form-control" id="x"></select>',
format(selectInput('x', NULL, NULL, selectize = FALSE))
))