Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Fix finding inputs with IDs containing spaces #3852

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions inst/www/shared/shiny.js
Original file line number Diff line number Diff line change
Expand Up @@ -5859,6 +5859,15 @@
return val;
return val.replace(/([!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, "\\$1");
}
function escapedIdSelector(val) {
val = $escape(val);
if (val.indexOf(" ") === -1)
return "#" + val;
console.warn("[shiny] Invalid ID, should not include spaces.", {
id: val
});
return '[id="'.concat(val, '"]');
}
function mapValues(obj, f) {
var newObj = {};
Object.keys(obj).forEach(function(key) {
Expand Down Expand Up @@ -18328,7 +18337,8 @@
});
addMessageHandler("inputMessages", function(message) {
for (var i = 0; i < message.length; i++) {
var $obj = (0, import_jquery38.default)(".shiny-bound-input#" + $escape(message[i].id));
var inputSelector = ".shiny-bound-input" + escapedIdSelector(message[i].id);
var $obj = (0, import_jquery38.default)(inputSelector);
var inputBinding = $obj.data("shiny-input-binding");
if ($obj.length > 0) {
if (!$obj.attr("aria-live"))
Expand Down Expand Up @@ -18593,7 +18603,7 @@
}
});
function getTabset(id) {
var $tabset = (0, import_jquery38.default)("#" + $escape(id));
var $tabset = (0, import_jquery38.default)(escapedIdSelector(id));
if ($tabset.length === 0)
throw "There is no tabsetPanel (or navbarPage or navlistPanel) with id equal to '" + id + "'";
return $tabset;
Expand Down
4 changes: 2 additions & 2 deletions inst/www/shared/shiny.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion inst/www/shared/shiny.min.js

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions inst/www/shared/shiny.min.js.map

Large diffs are not rendered by default.

14 changes: 11 additions & 3 deletions srcts/src/shiny/shinyapp.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import $ from "jquery";
import { $escape, hasOwnProperty, randomId, scopeExprToFunc } from "../utils";
import {
$escape,
escapedIdSelector,
hasOwnProperty,
randomId,
scopeExprToFunc,
} from "../utils";
import {
getShinyCreateWebsocket,
getShinyOnCustomMessage,
Expand Down Expand Up @@ -713,7 +719,9 @@ class ShinyApp {
(message: Array<{ id: string; message: unknown }>) => {
// inputMessages should be an array
for (let i = 0; i < message.length; i++) {
const $obj = $(".shiny-bound-input#" + $escape(message[i].id));
const inputSelector =
".shiny-bound-input" + escapedIdSelector(message[i].id);
const $obj = $(inputSelector);
const inputBinding: InputBinding = $obj.data("shiny-input-binding");

// Dispatch the message to the appropriate input object
Expand Down Expand Up @@ -940,7 +948,7 @@ class ShinyApp {
});

function getTabset(id: string) {
const $tabset = $("#" + $escape(id));
const $tabset = $(escapedIdSelector(id));

if ($tabset.length === 0)
throw (
Expand Down
10 changes: 10 additions & 0 deletions srcts/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,15 @@ function $escape(val: string | undefined): string | undefined {
return val.replace(/([!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, "\\$1");
}

// Returns a selector for an ID, preferring the #id syntax but falling back to
// [id="id"] if the ID contains spaces (with a warning).
function escapedIdSelector(val: string): string {
val = $escape(val);
if (val.indexOf(" ") === -1) return "#" + val;
console.warn("[shiny] Invalid ID, should not include spaces.", { id: val });
return `[id="${val}"]`;
}

// Maps a function over an object, preserving keys. Like the mapValues
// function from lodash.
function mapValues<T extends { [key: string]: any }, R>(
Expand Down Expand Up @@ -401,6 +410,7 @@ export {
asArray,
mergeSort,
$escape,
escapedIdSelector,
mapValues,
isnan,
_equal,
Expand Down
3 changes: 2 additions & 1 deletion srcts/types/src/utils/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ declare function asArray<T>(value: T | T[] | null | undefined): T[];
declare function mergeSort<Item>(list: Item[], sortfunc: (a: Item, b: Item) => boolean | number): Item[];
declare function $escape(val: undefined): undefined;
declare function $escape(val: string): string;
declare function escapedIdSelector(val: string): string;
declare function mapValues<T extends {
[key: string]: any;
}, R>(obj: T, f: (value: MapValuesUnion<T>, key: string, object: typeof obj) => R): MapWithResult<T, R>;
Expand All @@ -26,4 +27,4 @@ declare function updateLabel(labelTxt: string | undefined, labelNode: JQuery<HTM
declare function getComputedLinkColor(el: HTMLElement): string;
declare function isBS3(): boolean;
declare function toLowerCase<T extends string>(str: T): Lowercase<T>;
export { escapeHTML, randomId, strToBool, getStyle, padZeros, roundSignif, parseDate, formatDateUTC, makeResizeFilter, pixelRatio, scopeExprToFunc, asArray, mergeSort, $escape, mapValues, isnan, _equal, equal, compareVersion, updateLabel, getComputedLinkColor, hasOwnProperty, hasDefinedProperty, isBS3, toLowerCase, };
export { escapeHTML, randomId, strToBool, getStyle, padZeros, roundSignif, parseDate, formatDateUTC, makeResizeFilter, pixelRatio, scopeExprToFunc, asArray, mergeSort, $escape, escapedIdSelector, mapValues, isnan, _equal, equal, compareVersion, updateLabel, getComputedLinkColor, hasOwnProperty, hasDefinedProperty, isBS3, toLowerCase, };