mirror of
https://github.com/rstudio/shiny.git
synced 2026-01-11 16:08:19 -05:00
Compare commits
10 Commits
config-cle
...
vfill
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f3399568f | ||
|
|
f50076f2f9 | ||
|
|
c4e314ae04 | ||
|
|
b4a8236df5 | ||
|
|
a3743e2c90 | ||
|
|
cda59da698 | ||
|
|
51da80d381 | ||
|
|
412606c594 | ||
|
|
da2df5ac58 | ||
|
|
0e401d268d |
@@ -1,7 +1,7 @@
|
||||
Package: shiny
|
||||
Type: Package
|
||||
Title: Web Application Framework for R
|
||||
Version: 1.7.2.9000
|
||||
Version: 1.7.2.9001
|
||||
Authors@R: c(
|
||||
person("Winston", "Chang", role = c("aut", "cre"), email = "winston@rstudio.com", comment = c(ORCID = "0000-0002-1576-2126")),
|
||||
person("Joe", "Cheng", role = "aut", email = "joe@rstudio.com"),
|
||||
|
||||
@@ -57,17 +57,18 @@ bootstrapPage <- function(..., title = NULL, theme = NULL, lang = NULL) {
|
||||
ui <- attachDependencies(ui, bootstrapLib())
|
||||
}
|
||||
|
||||
setLang(ui, lang)
|
||||
setHtmlAttr(ui, "lang", lang)
|
||||
}
|
||||
|
||||
setLang <- function(ui, lang) {
|
||||
# Add lang attribute to be passed to renderPage function
|
||||
attr(ui, "lang") <- lang
|
||||
setHtmlAttr <- function(ui, attr_name, attr_value) {
|
||||
attrs <- getHtmlAttrs(ui)
|
||||
attrs[[attr_name]] <- attr_value
|
||||
attr(ui, "html_attrs") <- attrs
|
||||
ui
|
||||
}
|
||||
getLang <- function(ui) {
|
||||
getHtmlAttrs <- function(ui) {
|
||||
# Check if ui has lang attribute; otherwise, NULL
|
||||
attr(ui, "lang", exact = TRUE)
|
||||
attr(ui, "html_attrs", exact = TRUE)
|
||||
}
|
||||
|
||||
#' Bootstrap libraries
|
||||
@@ -331,10 +332,22 @@ fillPage <- function(..., padding = 0, title = NULL, bootstrap = TRUE,
|
||||
...
|
||||
)
|
||||
|
||||
ui <- setLang(ui, lang)
|
||||
ui <- setHtmlAttr(ui, "lang", lang)
|
||||
}
|
||||
|
||||
return(ui)
|
||||
# vfill-container rules live in bslib which means something like
|
||||
# fillPage(plotOutput("x")) won't work unless a bslib theme is used
|
||||
setBodyAttr(ui, "class", "vfill-container")
|
||||
}
|
||||
|
||||
setBodyAttr <- function(ui, attr_name, attr_value) {
|
||||
attrs <- getBodyAttrs(ui)
|
||||
attrs[[attr_name]] <- attr_value
|
||||
attr(ui, "body_attrs") <- attrs
|
||||
ui
|
||||
}
|
||||
getBodyAttrs <- function(ui) {
|
||||
attr(ui, "body_attrs", exact = TRUE)
|
||||
}
|
||||
|
||||
collapseSizes <- function(padding) {
|
||||
@@ -792,7 +805,7 @@ verbatimTextOutput <- function(outputId, placeholder = FALSE) {
|
||||
#' @name plotOutput
|
||||
#' @rdname plotOutput
|
||||
#' @export
|
||||
imageOutput <- function(outputId, width = "100%", height="400px",
|
||||
imageOutput <- function(outputId, width = NULL, height = NULL,
|
||||
click = NULL, dblclick = NULL, hover = NULL, brush = NULL,
|
||||
inline = FALSE) {
|
||||
|
||||
@@ -807,6 +820,7 @@ imageOutput <- function(outputId, width = "100%", height="400px",
|
||||
args <- list(
|
||||
id = outputId,
|
||||
class = "shiny-image-output",
|
||||
class = if (is.null(height)) "vfill-item",
|
||||
style = style
|
||||
)
|
||||
|
||||
@@ -1086,7 +1100,7 @@ imageOutput <- function(outputId, width = "100%", height="400px",
|
||||
#'
|
||||
#' }
|
||||
#' @export
|
||||
plotOutput <- function(outputId, width = "100%", height="400px",
|
||||
plotOutput <- function(outputId, width = NULL, height = NULL,
|
||||
click = NULL, dblclick = NULL, hover = NULL, brush = NULL,
|
||||
inline = FALSE) {
|
||||
|
||||
@@ -1135,16 +1149,18 @@ dataTableOutput <- function(outputId) {
|
||||
#' Create an HTML output element
|
||||
#'
|
||||
#' Render a reactive output variable as HTML within an application page. The
|
||||
#' text will be included within an HTML `div` tag, and is presumed to
|
||||
#' contain HTML content which should not be escaped.
|
||||
#' text will be included within an HTML `div` tag, and is presumed to contain
|
||||
#' HTML content which should not be escaped.
|
||||
#'
|
||||
#' `uiOutput` is intended to be used with `renderUI` on the server
|
||||
#' side. It is currently just an alias for `htmlOutput`.
|
||||
#' `uiOutput` is intended to be used with `renderUI` on the server side. It is
|
||||
#' currently just an alias for `htmlOutput`.
|
||||
#'
|
||||
#' @param outputId output variable to read the value from
|
||||
#' @param outputId output variable to read the value from.
|
||||
#' @param ... Other arguments to pass to the container tag function. This is
|
||||
#' useful for providing additional classes for the tag.
|
||||
#' @inheritParams textOutput
|
||||
#' @param fill Whether the output should be allowed to grow/shrink to the size
|
||||
#' of the `container`. Ignored when `inline = TRUE`.
|
||||
#' @return An HTML output element that can be included in a panel
|
||||
#' @examples
|
||||
#' htmlOutput("summary")
|
||||
@@ -1155,12 +1171,18 @@ dataTableOutput <- function(outputId) {
|
||||
#' )
|
||||
#' @export
|
||||
htmlOutput <- function(outputId, inline = FALSE,
|
||||
container = if (inline) span else div, ...)
|
||||
container = if (inline) span else div, fill = FALSE, ...)
|
||||
{
|
||||
if (any_unnamed(list(...))) {
|
||||
warning("Unnamed elements in ... will be replaced with dynamic UI.")
|
||||
}
|
||||
container(id = outputId, class="shiny-html-output", ...)
|
||||
|
||||
container(
|
||||
id = outputId,
|
||||
class = "shiny-html-output",
|
||||
class = if (fill && !inline) "vfill-container vfill-item",
|
||||
...
|
||||
)
|
||||
}
|
||||
|
||||
#' @rdname htmlOutput
|
||||
|
||||
11
R/shinyui.R
11
R/shinyui.R
@@ -29,7 +29,6 @@ withMathJax <- function(...) {
|
||||
}
|
||||
|
||||
renderPage <- function(ui, showcase=0, testMode=FALSE) {
|
||||
lang <- getLang(ui)
|
||||
|
||||
# If the ui is a NOT complete document (created by htmlTemplate()), then do some
|
||||
# preprocessing and make sure it's a complete document.
|
||||
@@ -38,13 +37,17 @@ renderPage <- function(ui, showcase=0, testMode=FALSE) {
|
||||
ui <- showcaseUI(ui)
|
||||
|
||||
# Wrap ui in body tag if it doesn't already have a single top-level body tag.
|
||||
if (!(inherits(ui, "shiny.tag") && ui$name == "body"))
|
||||
ui <- tags$body(ui)
|
||||
ui <- if (inherits(ui, "shiny.tag") && ui$name == "body") {
|
||||
tagAppendAttributes(ui, !!!getBodyAttrs(ui))
|
||||
} else {
|
||||
tags$body(ui, !!!getBodyAttrs(ui))
|
||||
}
|
||||
|
||||
# Put the body into the default template
|
||||
ui <- htmlTemplate(
|
||||
system_file("template", "default.html", package = "shiny"),
|
||||
lang = lang,
|
||||
|
||||
html_open = HTML(sub("</html>$", "", tags$html(!!!getHtmlAttrs(ui)))),
|
||||
body = ui,
|
||||
# this template is a complete HTML document
|
||||
document_ = TRUE
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html{{ if (isTRUE(nzchar(lang))) paste0(" lang=\"", lang, "\"") }}>
|
||||
{{html_open}}
|
||||
<head>
|
||||
{{ headContent() }}
|
||||
</head>
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
Selectize.define("selectize-plugin-a11y",function(c){var t=this,l=13;typeof t.accessibility=="undefined"&&(t.accessibility={}),t.accessibility.helpers={randomId:function(e){for(var a="",s=e||10,r="abcdefghijklmnopqrstuvwxyz0123456789",n=r.length,o=0;o<s;o++)a+=r[Math.floor(n*Math.random())];return a}},t.accessibility.liveRegion={$region:"",speak:function(e){var a=$("<div></div>");a.text(e),this.$region.html(a)},domListener:function(){var e=new MutationObserver(function(a){a.forEach(function(s){var r=$(s.target);if(r.hasClass("items"))if(r.hasClass("dropdown-active")){t.$control_input.attr("aria-expanded","true");var n=t.$dropdown_content[0].children;for(i=0;i<n.length;i++){var o=n[i].attributes;o.role||n[i].setAttribute("role","option"),o.id||n[i].setAttribute("id",t.accessibility.helpers.randomId())}}else t.$control_input.attr("aria-expanded","false"),t.$control_input.removeAttr("aria-activedescendant");else r.hasClass("active")&&r.attr("data-value")&&(t.$control_input.attr("aria-activedescendant",r.attr("id")),t.accessibility.liveRegion.speak(r.text(),500))})});e.observe(t.$dropdown[0],{attributes:!0,attributeFilter:["class"],subtree:!0,attributeOldValue:!0}),e.observe(t.$control[0],{attributes:!0,attributeFilter:["class"]}),e.observe(t.$control_input[0],{attributes:!0,attributeFilter:["value"]})},setAttributes:function(){this.$region.attr({"aria-live":"assertive",role:"log","aria-relevant":"additions","aria-atomic":"true"})},setStyles:function(){this.$region.css({position:"absolute",width:"1px",height:"1px","margin-top":"-1px",clip:"rect(1px, 1px, 1px, 1px)",overflow:"hidden"})},init:function(){this.$region=$("<div>"),this.setAttributes(),this.setStyles(),$("body").append(this.$region),this.domListener()}},this.setup=function(){var e=t.setup;return function(){e.apply(this,arguments);var a=t.accessibility.helpers.randomId(),s=t.accessibility.helpers.randomId();t.$control.on("keydown",function(r){r.keyCode===l&&(t.settings.openOnFocus?(t.settings.openOnFocus=!1,t.focus(),setTimeout(function(){t.settings.openOnFocus=!0},0)):t.focus())}),t.$control_input.attr({role:"combobox","aria-expanded":"false",haspopup:"listbox","aria-owns":s,"aria-label":t.$wrapper.closest("[data-accessibility-selectize-label]").attr("data-accessibility-selectize-label")}),t.$dropdown_content.attr({role:"listbox",id:s}),t.accessibility.liveRegion.init()}}(),this.destroy=function(){var e=t.destroy;return function(){return t.accessibility.liveRegion.$region.remove(),e.apply(this,arguments)}}()});
|
||||
"use strict";Selectize.define("selectize-plugin-a11y",function(c){var t=this,l=13;typeof t.accessibility=="undefined"&&(t.accessibility={}),t.accessibility.helpers={randomId:function(e){for(var a="",s=e||10,r="abcdefghijklmnopqrstuvwxyz0123456789",n=r.length,o=0;o<s;o++)a+=r[Math.floor(n*Math.random())];return a}},t.accessibility.liveRegion={$region:"",speak:function(e){var a=$("<div></div>");a.text(e),this.$region.html(a)},domListener:function(){var e=new MutationObserver(function(a){a.forEach(function(s){var r=$(s.target);if(r.hasClass("items"))if(r.hasClass("dropdown-active")){t.$control_input.attr("aria-expanded","true");var n=t.$dropdown_content[0].children;for(i=0;i<n.length;i++){var o=n[i].attributes;o.role||n[i].setAttribute("role","option"),o.id||n[i].setAttribute("id",t.accessibility.helpers.randomId())}}else t.$control_input.attr("aria-expanded","false"),t.$control_input.removeAttr("aria-activedescendant");else r.hasClass("active")&&r.attr("data-value")&&(t.$control_input.attr("aria-activedescendant",r.attr("id")),t.accessibility.liveRegion.speak(r.text(),500))})});e.observe(t.$dropdown[0],{attributes:!0,attributeFilter:["class"],subtree:!0,attributeOldValue:!0}),e.observe(t.$control[0],{attributes:!0,attributeFilter:["class"]}),e.observe(t.$control_input[0],{attributes:!0,attributeFilter:["value"]})},setAttributes:function(){this.$region.attr({"aria-live":"assertive",role:"log","aria-relevant":"additions","aria-atomic":"true"})},setStyles:function(){this.$region.css({position:"absolute",width:"1px",height:"1px","margin-top":"-1px",clip:"rect(1px, 1px, 1px, 1px)",overflow:"hidden"})},init:function(){this.$region=$("<div>"),this.setAttributes(),this.setStyles(),$("body").append(this.$region),this.domListener()}},this.setup=function(){var e=t.setup;return function(){e.apply(this,arguments);var a=t.accessibility.helpers.randomId(),s=t.accessibility.helpers.randomId();t.$control.on("keydown",function(r){r.keyCode===l&&(t.settings.openOnFocus?(t.settings.openOnFocus=!1,t.focus(),setTimeout(function(){t.settings.openOnFocus=!0},0)):t.focus())}),t.$control_input.attr({role:"combobox","aria-expanded":"false",haspopup:"listbox","aria-owns":s,"aria-label":t.$wrapper.closest("[data-accessibility-selectize-label]").attr("data-accessibility-selectize-label")}),t.$dropdown_content.attr({role:"listbox",id:s}),t.accessibility.liveRegion.init()}}(),this.destroy=function(){var e=t.destroy;return function(){return t.accessibility.liveRegion.$region.remove(),e.apply(this,arguments)}}()});
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,2 +1,2 @@
|
||||
/*! shiny 1.7.2.9000 | (c) 2012-2022 RStudio, PBC. | License: GPL-3 | file LICENSE */
|
||||
#showcase-well{border-radius:0}.shiny-code{background-color:#fff;margin-bottom:0}.shiny-code code{font-family:Menlo,Consolas,"Courier New",monospace}.shiny-code-container{margin-top:20px;clear:both}.shiny-code-container h3{display:inline;margin-right:15px}.showcase-header{font-size:16px;font-weight:normal}.showcase-code-link{text-align:right;padding:15px}#showcase-app-container{vertical-align:top}#showcase-code-tabs{margin-right:15px}#showcase-code-tabs pre{border:none;line-height:1em}#showcase-code-tabs .nav{margin-bottom:0}#showcase-code-tabs ul{margin-bottom:0}#showcase-code-tabs .tab-content{border-style:solid;border-color:#e5e5e5;border-width:0px 1px 1px 1px;overflow:auto;border-bottom-right-radius:4px;border-bottom-left-radius:4px}#showcase-app-code{width:100%}#showcase-code-position-toggle{float:right}#showcase-sxs-code{padding-top:20px;vertical-align:top}.showcase-code-license{display:block;text-align:right}#showcase-code-content pre{background-color:#fff}
|
||||
/*! shiny 1.7.2.9001 | (c) 2012-2022 RStudio, PBC. | License: GPL-3 | file LICENSE */
|
||||
#showcase-well{border-radius:0}.shiny-code{background-color:#fff;margin-bottom:0}.shiny-code code{font-family:Menlo,Consolas,Courier New,monospace}.shiny-code-container{margin-top:20px;clear:both}.shiny-code-container h3{display:inline;margin-right:15px}.showcase-header{font-size:16px;font-weight:400}.showcase-code-link{text-align:right;padding:15px}#showcase-app-container{vertical-align:top}#showcase-code-tabs{margin-right:15px}#showcase-code-tabs pre{border:none;line-height:1em}#showcase-code-tabs .nav,#showcase-code-tabs ul{margin-bottom:0}#showcase-code-tabs .tab-content{border-style:solid;border-color:#e5e5e5;border-width:0px 1px 1px 1px;overflow:auto;border-bottom-right-radius:4px;border-bottom-left-radius:4px}#showcase-app-code{width:100%}#showcase-code-position-toggle{float:right}#showcase-sxs-code{padding-top:20px;vertical-align:top}.showcase-code-license{display:block;text-align:right}#showcase-code-content pre{background-color:#fff}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,3 +1,3 @@
|
||||
/*! shiny 1.7.2.9000 | (c) 2012-2022 RStudio, PBC. | License: GPL-3 | file LICENSE */
|
||||
(function(){var a=eval;window.addEventListener("message",function(i){var e=i.data;e.code&&a(e.code)});})();
|
||||
/*! shiny 1.7.2.9001 | (c) 2012-2022 RStudio, PBC. | License: GPL-3 | file LICENSE */
|
||||
"use strict";(function(){var a=eval;window.addEventListener("message",function(i){var e=i.data;e.code&&a(e.code)});})();
|
||||
//# sourceMappingURL=shiny-testmode.js.map
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
"version": 3,
|
||||
"sources": ["../../../srcts/src/utils/eval.ts", "../../../srcts/extras/shiny-testmode.ts"],
|
||||
"sourcesContent": ["//esbuild.github.io/content-types/#direct-eval\n//tl/dr;\n// * Direct usage of `eval(\"x\")` is bad with bundled code.\n// * Instead, use indirect calls to `eval` such as `indirectEval(\"x\")`\n// * Even just renaming the function works well enough.\n// > This is known as \"indirect eval\" because eval is not being called directly, and so does not trigger the grammatical special case for direct eval in the JavaScript VM. You can call indirect eval using any syntax at all except for an expression of the exact form eval('x'). For example, var eval2 = eval; eval2('x') and [eval][0]('x') and window.eval('x') are all indirect eval calls.\n// > When you use indirect eval, the code is evaluated in the global scope instead of in the inline scope of the caller.\nvar indirectEval = eval;\nexport { indirectEval };", "/* eslint-disable unicorn/filename-case */\nimport { indirectEval } from \"../src/utils/eval\"; // Listen for messages from parent frame. This file is only added when the\n// shiny.testmode option is TRUE.\n\nwindow.addEventListener(\"message\", function (e) {\n var message = e.data;\n if (message.code) indirectEval(message.code);\n});"],
|
||||
"mappings": ";YAOA,GAAI,GAAe,KCHnB,OAAO,iBAAiB,UAAW,SAAU,EAAG,CAC9C,GAAI,GAAU,EAAE,KAChB,AAAI,EAAQ,MAAM,EAAa,EAAQ",
|
||||
"names": []
|
||||
"mappings": ";yBAOA,IAAIA,EAAe,KCHnB,OAAO,iBAAiB,UAAW,SAAUC,EAAG,CAC9C,IAAIC,EAAUD,EAAE,KACZC,EAAQ,MAAMC,EAAaD,EAAQ,IAAI,CAC7C,CAAC",
|
||||
"names": ["indirectEval", "e", "message", "indirectEval"]
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
4
inst/www/shared/shiny.min.css
vendored
4
inst/www/shared/shiny.min.css
vendored
File diff suppressed because one or more lines are too long
4
inst/www/shared/shiny.min.js
vendored
4
inst/www/shared/shiny.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -86,6 +86,11 @@ pre.shiny-text-output {
|
||||
}
|
||||
}
|
||||
|
||||
.shiny-image-output, .shiny-plot-output {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
#shiny-disconnected-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
||||
@@ -9,19 +9,29 @@ htmlOutput(
|
||||
outputId,
|
||||
inline = FALSE,
|
||||
container = if (inline) span else div,
|
||||
fill = FALSE,
|
||||
...
|
||||
)
|
||||
|
||||
uiOutput(outputId, inline = FALSE, container = if (inline) span else div, ...)
|
||||
uiOutput(
|
||||
outputId,
|
||||
inline = FALSE,
|
||||
container = if (inline) span else div,
|
||||
fill = FALSE,
|
||||
...
|
||||
)
|
||||
}
|
||||
\arguments{
|
||||
\item{outputId}{output variable to read the value from}
|
||||
\item{outputId}{output variable to read the value from.}
|
||||
|
||||
\item{inline}{use an inline (\code{span()}) or block container (\code{div()})
|
||||
for the output}
|
||||
|
||||
\item{container}{a function to generate an HTML element to contain the text}
|
||||
|
||||
\item{fill}{Whether the output should be allowed to grow/shrink to the size
|
||||
of the \code{container}. Ignored when \code{inline = TRUE}.}
|
||||
|
||||
\item{...}{Other arguments to pass to the container tag function. This is
|
||||
useful for providing additional classes for the tag.}
|
||||
}
|
||||
@@ -30,12 +40,12 @@ An HTML output element that can be included in a panel
|
||||
}
|
||||
\description{
|
||||
Render a reactive output variable as HTML within an application page. The
|
||||
text will be included within an HTML \code{div} tag, and is presumed to
|
||||
contain HTML content which should not be escaped.
|
||||
text will be included within an HTML \code{div} tag, and is presumed to contain
|
||||
HTML content which should not be escaped.
|
||||
}
|
||||
\details{
|
||||
\code{uiOutput} is intended to be used with \code{renderUI} on the server
|
||||
side. It is currently just an alias for \code{htmlOutput}.
|
||||
\code{uiOutput} is intended to be used with \code{renderUI} on the server side. It is
|
||||
currently just an alias for \code{htmlOutput}.
|
||||
}
|
||||
\examples{
|
||||
htmlOutput("summary")
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
\usage{
|
||||
imageOutput(
|
||||
outputId,
|
||||
width = "100\%",
|
||||
height = "400px",
|
||||
width = NULL,
|
||||
height = NULL,
|
||||
click = NULL,
|
||||
dblclick = NULL,
|
||||
hover = NULL,
|
||||
@@ -18,8 +18,8 @@ imageOutput(
|
||||
|
||||
plotOutput(
|
||||
outputId,
|
||||
width = "100\%",
|
||||
height = "400px",
|
||||
width = NULL,
|
||||
height = NULL,
|
||||
click = NULL,
|
||||
dblclick = NULL,
|
||||
hover = NULL,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"homepage": "https://shiny.rstudio.com",
|
||||
"repository": "github:rstudio/shiny",
|
||||
"name": "@types/rstudio-shiny",
|
||||
"version": "1.7.2-alpha.9000",
|
||||
"version": "1.7.2-alpha.9001",
|
||||
"license": "GPL-3.0-only",
|
||||
"main": "",
|
||||
"browser": "",
|
||||
@@ -23,7 +23,7 @@
|
||||
"@types/bootstrap-datepicker": "0.0.14",
|
||||
"@types/datatables.net": "^1.10.19",
|
||||
"@types/ion-rangeslider": "2.3.0",
|
||||
"@types/jquery": "patch:@types/jquery@3.5.5#./srcts/patch/types-jquery.patch",
|
||||
"@types/jquery": "3.5.14",
|
||||
"@types/selectize": "0.12.34"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -59,6 +59,7 @@
|
||||
"eslint-plugin-jest-dom": "^4.0.2",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-unicorn": "^43.0.2",
|
||||
"fs-readdir-recursive": "^1.1.0",
|
||||
"ion-rangeslider": "2.3.1",
|
||||
"jest": "^26.6.3",
|
||||
"jquery": "3.6.0",
|
||||
|
||||
97
srcts/build/_jquery.ts
Normal file
97
srcts/build/_jquery.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
Make sure all `*.ts` files contain `"jquery"` import statements to properly scope `jquery`.
|
||||
|
||||
Prior behavior:
|
||||
- Use a patch file to remove globally declared `$` variable
|
||||
- PR: https://github.com/rstudio/shiny/pull/3296/commits/169318382d1d00927d0148a16fde4c96a291a602
|
||||
Prior reasoning:
|
||||
- Only allow for jQuery type definitions to exist if imported.
|
||||
- This is problematic as it can lead to improperly scoped values of `$`
|
||||
- Ex:
|
||||
* If `a.ts` imports jquery, then `b.ts` can see the global definition of `$`
|
||||
even though `b.ts` does not import jquery.
|
||||
* If `$` is not scoped / encapsulated, then it is possible to have
|
||||
inconsistent versions of jquery executing within the shiny bundle.
|
||||
Related:
|
||||
- Open Issue ('16): https://github.com/DefinitelyTyped/DefinitelyTyped/issues/11187
|
||||
- Closed stale PR ('19): https://github.com/DefinitelyTyped/DefinitelyTyped/pull/40295/files
|
||||
- Unsolved Issue ('14): https://github.com/DefinitelyTyped/DefinitelyTyped/issues/1564
|
||||
- Multiple `$` conflicts ('22): https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/60443
|
||||
- Bandaid PR ('22): https://github.com/DefinitelyTyped/DefinitelyTyped/pull/60444
|
||||
|
||||
Approach within this file:
|
||||
* For every `*.ts` file:
|
||||
* Do not use `jQuery` (use `$`!)
|
||||
* If utilizing `$`
|
||||
* Require `jquery` import statement
|
||||
- Advantages:
|
||||
- Does not require a yarn patch file or separate GitHub repo containing the patched type definitions.
|
||||
- Disadvantages:
|
||||
- Variable reassignment isn't caught `jq = $; jq(divs)`. (This should not happen, but it is possible.)
|
||||
- Only tested when bundling is started, not on every file change.
|
||||
- PR: https://github.com/rstudio/shiny/pull/3710
|
||||
*/
|
||||
|
||||
import fs from "fs";
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore; Type definitions are not found
|
||||
import readdirRecursive from "fs-readdir-recursive";
|
||||
import { isUndefined } from "lodash";
|
||||
|
||||
const verifyJqueryUsage = async function (filename: string): Promise<void> {
|
||||
const contents = await fs.promises.readFile(filename, "utf8");
|
||||
const lines = contents.toString().split("\n");
|
||||
|
||||
// Find if using `jQuery` in the file
|
||||
const jqueryMatch = lines.find((line) => {
|
||||
return line.includes("jQuery.") || line.includes("jQuery(");
|
||||
});
|
||||
|
||||
if (!isUndefined(jqueryMatch)) {
|
||||
throw (
|
||||
`Using \`jQuery\` in file: ${filename}\n` +
|
||||
`Match:\n${jqueryMatch}\n` +
|
||||
"Please use `$` instead of `jQuery`\n" +
|
||||
"See file ./srcts/build/_jquery.ts for more details"
|
||||
);
|
||||
}
|
||||
|
||||
// Find if using `$` in the file
|
||||
const dollarMatch = lines.find((line) => {
|
||||
return line.includes("$.") || line.includes("$(");
|
||||
});
|
||||
|
||||
if (isUndefined(dollarMatch)) {
|
||||
// No match found. Not using jquery
|
||||
return;
|
||||
}
|
||||
|
||||
// Using jquery, find that it is being imported
|
||||
const importJquery = 'import $ from "jquery";';
|
||||
const hasJqueryImport = lines.includes(importJquery);
|
||||
|
||||
if (!hasJqueryImport) {
|
||||
// Not importing jquery, yell
|
||||
throw (
|
||||
`Using \`$\` in file: ${filename}\n` +
|
||||
`Match:\n${dollarMatch}\n` +
|
||||
`Please call \`${importJquery}\` at the top of the file.\n` +
|
||||
"See file ./srcts/build/_jquery.ts for more details"
|
||||
);
|
||||
}
|
||||
|
||||
// Using jquery and importing it;
|
||||
return;
|
||||
};
|
||||
|
||||
const verifyJqueryImport = async function (dir = "."): Promise<void> {
|
||||
const tsFiles = (readdirRecursive(dir) as string[])
|
||||
.filter((path: string) => path.endsWith(".ts"))
|
||||
.map((path) => dir + "/" + path);
|
||||
|
||||
// Run all checks in parallel
|
||||
await Promise.all(tsFiles.map((file) => verifyJqueryUsage(file)));
|
||||
return;
|
||||
};
|
||||
|
||||
export { verifyJqueryImport };
|
||||
@@ -6,6 +6,7 @@
|
||||
import { banner, build, outDir, shinyDesc, babelPlugin } from "./_build";
|
||||
import globalsPlugin from "esbuild-plugin-globals";
|
||||
import type { BuildOptions } from "esbuild";
|
||||
import { verifyJqueryImport } from "./_jquery";
|
||||
|
||||
const opts: BuildOptions = {
|
||||
entryPoints: ["srcts/src/index.ts"],
|
||||
@@ -26,12 +27,21 @@ const opts: BuildOptions = {
|
||||
banner: banner,
|
||||
};
|
||||
|
||||
build({
|
||||
...opts,
|
||||
outfile: outDir + "shiny.js",
|
||||
});
|
||||
build({
|
||||
...opts,
|
||||
outfile: outDir + "shiny.min.js",
|
||||
minify: true,
|
||||
});
|
||||
// Make sure all ts files contain jquery import statements before building
|
||||
verifyJqueryImport("srcts/src")
|
||||
.then(() => {
|
||||
Promise.all([
|
||||
build({
|
||||
...opts,
|
||||
outfile: outDir + "shiny.js",
|
||||
}),
|
||||
build({
|
||||
...opts,
|
||||
outfile: outDir + "shiny.min.js",
|
||||
minify: true,
|
||||
}),
|
||||
]);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Error:\n" + err);
|
||||
});
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
# `yarn` Patch files
|
||||
|
||||
* `types-jquery.patch`
|
||||
* Do not export `$` as a globally available variable. When developing TS code, I like to have full control over the variables. It is good to have a record of where everything comes from. Shiny can not use the latest jQuery loaded onto the page and needs to use a scoped `jQuery` variable. In the end, we can shim the `jquery` import to be `window.jQuery`
|
||||
* `yarn_pnp.patch`
|
||||
* This file is currently not used and is outdated.
|
||||
* This provides a good game plan on how to use PnP with Yarn once esbuild can easily be integrated with Yarn PnP.
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
diff --git a/misc.d.ts b/misc.d.ts
|
||||
index 126d374477db459e1a251f5af548e88b46f43cdd..948cfb287b0bfa6057f3ccbcd013579aef07a29a 100644
|
||||
--- a/misc.d.ts
|
||||
+++ b/misc.d.ts
|
||||
@@ -6618,7 +6618,7 @@ $( "#checkMetaKey" ).click(function( event ) {
|
||||
}
|
||||
|
||||
declare const jQuery: JQueryStatic;
|
||||
-declare const $: JQueryStatic;
|
||||
+// declare const $: JQueryStatic;
|
||||
|
||||
type _Event = Event;
|
||||
type _UIEvent = UIEvent;
|
||||
@@ -6643,6 +6643,6 @@ interface SymbolConstructor {
|
||||
readonly toStringTag: symbol;
|
||||
}
|
||||
|
||||
-declare var Symbol: SymbolConstructor;
|
||||
+// declare var Symbol: SymbolConstructor;
|
||||
|
||||
// #endregion
|
||||
@@ -24,7 +24,7 @@ $(document).on(
|
||||
function (e: Event) {
|
||||
e;
|
||||
|
||||
const evt: FileDownloadEvent = jQuery.Event("shiny:filedownload");
|
||||
const evt: FileDownloadEvent = $.Event("shiny:filedownload");
|
||||
|
||||
evt.name = this.id;
|
||||
evt.href = this.href;
|
||||
|
||||
@@ -11,7 +11,7 @@ class InputEventDecorator implements InputPolicy {
|
||||
}
|
||||
|
||||
setInput(nameType: string, value: unknown, opts: InputPolicyOpts): void {
|
||||
const evt = jQuery.Event("shiny:inputchanged") as ShinyEventInputChanged;
|
||||
const evt = $.Event("shiny:inputchanged") as ShinyEventInputChanged;
|
||||
|
||||
const input = splitInputNameType(nameType);
|
||||
|
||||
|
||||
@@ -43,6 +43,8 @@ type OnSuccessRequest = (value: ResponseValue) => void;
|
||||
type OnErrorRequest = (err: string) => void;
|
||||
type InputValues = { [key: string]: unknown };
|
||||
|
||||
type MessageValue = Parameters<WebSocket["send"]>[0];
|
||||
|
||||
//// 2021/03 - TypeScript conversion note:
|
||||
// These four variables were moved from being internally defined to being defined globally within the file.
|
||||
// Before the TypeScript conversion, the values where attached to `window.Shiny.addCustomMessageHandler()`.
|
||||
@@ -127,7 +129,7 @@ class ShinyApp {
|
||||
// Conditional bindings (show/hide element based on expression)
|
||||
$conditionals = {};
|
||||
|
||||
$pendingMessages: string[] = [];
|
||||
$pendingMessages: MessageValue[] = [];
|
||||
$activeRequests: {
|
||||
[key: number]: { onSuccess: OnSuccessRequest; onError: OnErrorRequest };
|
||||
} = {};
|
||||
@@ -381,7 +383,7 @@ class ShinyApp {
|
||||
onError: onError,
|
||||
};
|
||||
|
||||
let msg = JSON.stringify({
|
||||
let msg: Blob | string = JSON.stringify({
|
||||
method: method,
|
||||
args: args,
|
||||
tag: requestId,
|
||||
@@ -423,13 +425,13 @@ class ShinyApp {
|
||||
|
||||
const blob: Blob = new Blob(payload);
|
||||
|
||||
msg = blob as unknown as string;
|
||||
msg = blob;
|
||||
}
|
||||
|
||||
this.$sendMsg(msg);
|
||||
}
|
||||
|
||||
$sendMsg(msg: string): void {
|
||||
$sendMsg(msg: MessageValue): void {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
if (!this.$socket!.readyState) {
|
||||
this.$pendingMessages.push(msg);
|
||||
@@ -446,7 +448,7 @@ class ShinyApp {
|
||||
delete this.$values[name];
|
||||
|
||||
const binding = this.$bindings[name];
|
||||
const evt: ShinyEventError = jQuery.Event("shiny:error");
|
||||
const evt: ShinyEventError = $.Event("shiny:error");
|
||||
|
||||
evt.name = name;
|
||||
evt.error = error;
|
||||
@@ -459,7 +461,7 @@ class ShinyApp {
|
||||
|
||||
receiveOutput<T>(name: string, value: T): T | undefined {
|
||||
const binding = this.$bindings[name];
|
||||
const evt: ShinyEventValue = jQuery.Event("shiny:value");
|
||||
const evt: ShinyEventValue = $.Event("shiny:value");
|
||||
|
||||
evt.name = name;
|
||||
evt.value = value;
|
||||
@@ -618,7 +620,7 @@ class ShinyApp {
|
||||
msgObj.custom[type] = data;
|
||||
}
|
||||
|
||||
const evt: ShinyEventMessage = jQuery.Event("shiny:message");
|
||||
const evt: ShinyEventMessage = $.Event("shiny:message");
|
||||
|
||||
evt.message = msgObj;
|
||||
$(document).trigger(evt);
|
||||
@@ -698,8 +700,7 @@ class ShinyApp {
|
||||
if ($obj.length > 0) {
|
||||
if (!$obj.attr("aria-live")) $obj.attr("aria-live", "polite");
|
||||
const el = $obj[0];
|
||||
const evt: ShinyEventUpdateInput =
|
||||
jQuery.Event("shiny:updateinput");
|
||||
const evt: ShinyEventUpdateInput = $.Event("shiny:updateinput");
|
||||
|
||||
evt.message = message[i].message;
|
||||
evt.binding = inputBinding;
|
||||
@@ -876,7 +877,7 @@ class ShinyApp {
|
||||
message.selector +
|
||||
'") could not be found in the DOM.'
|
||||
);
|
||||
renderHtml(message.content.html, $([]).get(0), message.content.deps);
|
||||
renderHtml(message.content.html, $([]), message.content.deps);
|
||||
} else {
|
||||
targets.each(function (i, target) {
|
||||
renderContent(target, message.content, message.where);
|
||||
@@ -1202,7 +1203,7 @@ class ShinyApp {
|
||||
// value for the tabset gets updated (i.e. input$tabsetId
|
||||
// should be null if there are no tabs).
|
||||
const destTabValue = getFirstTab($tabset);
|
||||
const evt: ShinyEventUpdateInput = jQuery.Event("shiny:updateinput");
|
||||
const evt: ShinyEventUpdateInput = $.Event("shiny:updateinput");
|
||||
|
||||
evt.binding = inputBinding;
|
||||
$tabset.trigger(evt);
|
||||
|
||||
@@ -66,7 +66,7 @@ function registerNames(s: string[] | string): void {
|
||||
// Inserts new content into document head
|
||||
function addToHead(head: string) {
|
||||
if (head.length > 0) {
|
||||
const tempDiv = $("<div>" + head + "</div>").get(0);
|
||||
const tempDiv = $("<div>" + head + "</div>").get(0) as HTMLDivElement;
|
||||
const $head = $("head");
|
||||
|
||||
while (tempDiv.hasChildNodes()) {
|
||||
|
||||
5
srcts/types/src/shiny/shinyapp.d.ts
vendored
5
srcts/types/src/shiny/shinyapp.d.ts
vendored
@@ -15,6 +15,7 @@ declare type OnErrorRequest = (err: string) => void;
|
||||
declare type InputValues = {
|
||||
[key: string]: unknown;
|
||||
};
|
||||
declare type MessageValue = Parameters<WebSocket["send"]>[0];
|
||||
declare function addCustomMessageHandler(type: string, handler: Handler): void;
|
||||
declare class ShinyApp {
|
||||
$socket: ShinyWebSocket | null;
|
||||
@@ -34,7 +35,7 @@ declare class ShinyApp {
|
||||
[key: string]: ErrorsMessageValue;
|
||||
};
|
||||
$conditionals: {};
|
||||
$pendingMessages: string[];
|
||||
$pendingMessages: MessageValue[];
|
||||
$activeRequests: {
|
||||
[key: number]: {
|
||||
onSuccess: OnSuccessRequest;
|
||||
@@ -60,7 +61,7 @@ declare class ShinyApp {
|
||||
onDisconnected(): void;
|
||||
onConnected(): void;
|
||||
makeRequest(method: string, args: unknown[], onSuccess: OnSuccessRequest, onError: OnErrorRequest, blobs: Array<ArrayBuffer | Blob | string> | undefined): void;
|
||||
$sendMsg(msg: string): void;
|
||||
$sendMsg(msg: MessageValue): void;
|
||||
receiveError(name: string, error: ErrorsMessageValue): void;
|
||||
receiveOutput<T>(name: string, value: T): T | undefined;
|
||||
bindOutput(id: string, binding: OutputBindingAdapter): OutputBindingAdapter;
|
||||
|
||||
5
srcts/types/src/utils/blob.d.ts
vendored
5
srcts/types/src/utils/blob.d.ts
vendored
@@ -1,5 +0,0 @@
|
||||
declare type BlobBuilderConstructor = typeof window.MSBlobBuilder;
|
||||
declare function setBlobBuilder(blobBuilderClass_: BlobBuilderConstructor): void;
|
||||
declare function makeBlob(parts: BlobPart[]): Blob;
|
||||
export { makeBlob, setBlobBuilder };
|
||||
export type { BlobBuilderConstructor };
|
||||
3
srcts/types/src/window/blobBuilder.d.ts
vendored
3
srcts/types/src/window/blobBuilder.d.ts
vendored
@@ -1,3 +0,0 @@
|
||||
import type { BlobBuilderConstructor } from "../utils/blob";
|
||||
declare function windowBlobBuilder(): BlobBuilderConstructor;
|
||||
export { windowBlobBuilder };
|
||||
@@ -1,7 +1,7 @@
|
||||
library(magrittr)
|
||||
|
||||
version <- "3.6.0"
|
||||
version_types <- "3.5.5"
|
||||
version_types <- "3.5.14"
|
||||
|
||||
jq_cdn_download <- function(version) {
|
||||
Map(
|
||||
@@ -58,7 +58,7 @@ withr::with_dir(
|
||||
exit_code <- system(paste0("yarn add --dev jquery@", version))
|
||||
if (exit_code != 0) stop("yarn could not install jquery")
|
||||
|
||||
exit_code <- system(paste0("yarn add @types/jquery@patch:@types/jquery@", version_types, "#./srcts/patch/types-jquery.patch"))
|
||||
exit_code <- system(paste0("yarn add @types/jquery@", version_types))
|
||||
if (exit_code != 0) stop("yarn could not install @types/jquery")
|
||||
}
|
||||
)
|
||||
|
||||
20
yarn.lock
20
yarn.lock
@@ -1918,7 +1918,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/jquery@3.5.5, @types/jquery@npm:*":
|
||||
"@types/jquery@npm:*":
|
||||
version: 3.5.5
|
||||
resolution: "@types/jquery@npm:3.5.5"
|
||||
dependencies:
|
||||
@@ -1927,12 +1927,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/jquery@patch:@types/jquery@3.5.5#./srcts/patch/types-jquery.patch::locator=%40types%2Frstudio-shiny%40workspace%3A.":
|
||||
version: 3.5.5
|
||||
resolution: "@types/jquery@patch:@types/jquery@npm%3A3.5.5#./srcts/patch/types-jquery.patch::version=3.5.5&hash=a7a8f9&locator=%40types%2Frstudio-shiny%40workspace%3A."
|
||||
"@types/jquery@npm:3.5.14":
|
||||
version: 3.5.14
|
||||
resolution: "@types/jquery@npm:3.5.14"
|
||||
dependencies:
|
||||
"@types/sizzle": "*"
|
||||
checksum: aa4ba94f98a085ae77b8717a6ce81a05d7647f0df5f87f160c21e7772d60f7ed20ba951886e36fe8d0205882dfc62107b722df4d638ae6d3b4af9bfed227e289
|
||||
checksum: 159d6f804ed1a204b3f79f2d591a271d82e866bd45bd49fb6ef40561a25dbe0f47ec7815681b44cc2db5598425f72811e7e80ab0e983d980470998ac56feb375
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1999,7 +1999,7 @@ __metadata:
|
||||
"@types/highlightjs": ^9.12.1
|
||||
"@types/ion-rangeslider": 2.3.0
|
||||
"@types/jest": ^26.0.23
|
||||
"@types/jquery": "patch:@types/jquery@3.5.5#./srcts/patch/types-jquery.patch"
|
||||
"@types/jquery": 3.5.14
|
||||
"@types/jqueryui": 1.12.16
|
||||
"@types/lodash": ^4.14.170
|
||||
"@types/node": ^15.6.1
|
||||
@@ -2022,6 +2022,7 @@ __metadata:
|
||||
eslint-plugin-jest-dom: ^4.0.2
|
||||
eslint-plugin-prettier: ^4.2.1
|
||||
eslint-plugin-unicorn: ^43.0.2
|
||||
fs-readdir-recursive: ^1.1.0
|
||||
ion-rangeslider: 2.3.1
|
||||
jest: ^26.6.3
|
||||
jquery: 3.6.0
|
||||
@@ -4899,6 +4900,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fs-readdir-recursive@npm:^1.1.0":
|
||||
version: 1.1.0
|
||||
resolution: "fs-readdir-recursive@npm:1.1.0"
|
||||
checksum: 29d50f3d2128391c7fc9fd051c8b7ea45bcc8aa84daf31ef52b17218e20bfd2bd34d02382742801954cc8d1905832b68227f6b680a666ce525d8b6b75068ad1e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fs.realpath@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "fs.realpath@npm:1.0.0"
|
||||
|
||||
Reference in New Issue
Block a user