Skip to content

Commit abde5ae

Browse files
author
Ryan Patrick Kyle
committed
✨ initial support for attributes
1 parent 4d234cb commit abde5ae

File tree

3 files changed

+85
-30
lines changed

3 files changed

+85
-30
lines changed

R/dash.R

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,13 @@ Dash <- R6::R6Class(
4545
#' @param requests_pathname_prefix Character. A prefix applied to request endpoints
4646
#' made by Dash's front-end. Environment variable is `DASH_REQUESTS_PATHNAME_PREFIX`.
4747
#' @param external_scripts List. An optional list of valid URLs from which
48-
#' to serve JavaScript source for rendered pages.
48+
#' to serve JavaScript source for rendered pages. Each entry can be a string (the URL)
49+
#' or a list with `src` (the URL) and optionally other `<script>` tag attributes such
50+
#' as `integrity` and `crossorigin`.
4951
#' @param external_stylesheets List. An optional list of valid URLs from which
50-
#' to serve CSS for rendered pages.
52+
#' to serve CSS for rendered pages. Each entry can be a string (the URL) or a list
53+
#' with `href` (the URL) and optionally other `<link>` tag attributes such as
54+
#' `rel`, `integrity` and `crossorigin`.
5155
#' @param compress Logical. Whether to try to compress files and data served by Fiery.
5256
#' By default, `brotli` is attempted first, then `gzip`, then the `deflate` algorithm,
5357
#' before falling back to `identity`.
@@ -1578,7 +1582,7 @@ Dash <- R6::R6Class(
15781582

15791583
# collect CSS assets from dependencies
15801584
if (!(is.null(private$asset_map$css))) {
1581-
css_assets <- generate_css_dist_html(href = paste0(private$assets_url_path, names(private$asset_map$css)),
1585+
css_assets <- generate_css_dist_html(tagdata = paste0(private$assets_url_path, names(private$asset_map$css)),
15821586
local = TRUE,
15831587
local_path = private$asset_map$css,
15841588
prefix = self$config$requests_pathname_prefix)
@@ -1596,7 +1600,7 @@ Dash <- R6::R6Class(
15961600
# collect JS assets from dependencies
15971601
#
15981602
if (!(is.null(private$asset_map$scripts))) {
1599-
scripts_assets <- generate_js_dist_html(href = paste0(private$assets_url_path, names(private$asset_map$scripts)),
1603+
scripts_assets <- generate_js_dist_html(tagdata = paste0(private$assets_url_path, names(private$asset_map$scripts)),
16001604
local = TRUE,
16011605
local_path = private$asset_map$scripts,
16021606
prefix = self$config$requests_pathname_prefix)

R/utils.R

Lines changed: 71 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ render_dependencies <- function(dependencies, local = TRUE, prefix=NULL) {
157157
# as in Dash for Python
158158
if ("script" %in% names(dep) && tools::file_ext(dep[["script"]]) != "map") {
159159
if (!(is_local) & !(is.null(dep$src$href))) {
160-
html <- generate_js_dist_html(href = dep$src$href)
160+
html <- generate_js_dist_html(tagdata = dep$src$href)
161161
} else {
162162
script_mtime <- file.mtime(getDependencyPath(dep))
163163
modtime <- as.integer(script_mtime)
@@ -172,7 +172,7 @@ render_dependencies <- function(dependencies, local = TRUE, prefix=NULL) {
172172
"&m=",
173173
modified)
174174

175-
html <- generate_js_dist_html(href = dep[["script"]], as_is = TRUE)
175+
html <- generate_js_dist_html(tagdata = dep[["script"]], as_is = TRUE)
176176
}
177177
} else if (!(is_local) & "stylesheet" %in% names(dep) & src == "href") {
178178
html <- generate_css_dist_html(href = paste(dep[["src"]][["href"]],
@@ -192,20 +192,20 @@ render_dependencies <- function(dependencies, local = TRUE, prefix=NULL) {
192192
"?v=",
193193
dep$version)
194194

195-
html <- generate_css_dist_html(href = sheetpath, as_is = TRUE)
195+
html <- generate_css_dist_html(tagdata = sheetpath, as_is = TRUE)
196196
} else {
197197
sheetpath <- paste0(dep[["src"]][["file"]],
198198
dep[["stylesheet"]],
199199
"?v=",
200200
dep$version)
201201

202-
html <- generate_css_dist_html(href = sheetpath, as_is = TRUE)
202+
html <- generate_css_dist_html(tagdata = sheetpath, as_is = TRUE)
203203
}
204204

205205
} else {
206206
sheetpath <- paste0(dep[["src"]][["file"]],
207207
dep[["stylesheet"]])
208-
html <- generate_css_dist_html(href = sheetpath, as_is = TRUE)
208+
html <- generate_css_dist_html(tagdata = sheetpath, as_is = TRUE)
209209
}
210210
}
211211
})
@@ -536,51 +536,98 @@ get_mimetype <- function(filename) {
536536
empty = "application/octet-stream"))
537537
}
538538

539-
generate_css_dist_html <- function(href,
539+
generate_css_dist_html <- function(tagdata,
540540
local = FALSE,
541541
local_path = NULL,
542542
prefix = NULL,
543543
as_is = FALSE) {
544+
attribs <- names(tagdata)
545+
allowed_attribs <- c("as",
546+
"crossorigin",
547+
"disabled",
548+
"href",
549+
"hreflang",
550+
"importance",
551+
"integrity",
552+
"media",
553+
"referrerpolicy",
554+
"rel",
555+
"sizes",
556+
"title",
557+
"type",
558+
"methods",
559+
"prefetch",
560+
"target",
561+
"charset",
562+
"rev")
563+
if (!all(attribs %in% allowed_attribs)) {
564+
stop(sprintf("The following specified stylesheet attributes are invalid: ",
565+
paste0(setdiff(attribs, allowed_attribs), collapse=", ")), call. = FALSE)
566+
}
544567
if (!(local)) {
545-
if (grepl("^(?:http(s)?:\\/\\/)?[\\w.-]+(?:\\.[\\w\\.-]+)+[\\w\\-\\._~:/?#[\\]@!\\$&'\\(\\)\\*\\+,;=.]+$",
546-
href,
547-
perl=TRUE) || as_is) {
548-
sprintf("<link href=\"%s\" rel=\"stylesheet\">", href)
568+
if (any(grepl("^(?:http(s)?:\\/\\/)?[\\w.-]+(?:\\.[\\w\\.-]+)+[\\w\\-\\._~:/?#[\\]@!\\$&'\\(\\)\\*\\+,;=.]+$",
569+
tagdata,
570+
perl=TRUE)) || as_is) {
571+
if (is.list(tagdata))
572+
glue::glue('<link ', glue::glue_collapse(glue::glue('{attribs}="{tagdata}"'), sep=" "), ' rel="stylesheet">')
573+
else
574+
glue::glue('<link ', glue::glue('href="{tagdata}"'), ' rel="stylesheet">')
549575
}
550576
else
551577
stop(sprintf("Invalid URL supplied in external_stylesheets. Please check the syntax used for this parameter."), call. = FALSE)
552578
} else {
553579
# strip leading slash from href if present
580+
if (is.list(tagdata))
581+
href <- tagdata$src
582+
else
583+
href <- tagdata
554584
href <- sub("^/", "", href)
555585
modified <- as.integer(file.mtime(local_path))
556-
sprintf("<link href=\"%s%s?m=%s\" rel=\"stylesheet\">",
557-
prefix,
558-
href,
559-
modified)
586+
glue::glue('<link href="{prefix}{href}?m={modified}" rel="stylesheet">')
560587
}
561588
}
562589

563-
generate_js_dist_html <- function(href,
590+
generate_js_dist_html <- function(tagdata,
564591
local = FALSE,
565592
local_path = NULL,
566593
prefix = NULL,
567594
as_is = FALSE) {
595+
attribs <- names(tagdata)
596+
allowed_attribs <- c("async",
597+
"crossorigin",
598+
"defer",
599+
"integrity",
600+
"nomodule",
601+
"nonce",
602+
"referrerpolicy",
603+
"src",
604+
"type",
605+
"charset",
606+
"language")
607+
if (!all(attribs %in% allowed_attribs)) {
608+
stop(sprintf("The following specified script attributes are invalid: ",
609+
paste0(setdiff(attribs, allowed_attribs), collapse=", ")), call. = FALSE)
610+
}
568611
if (!(local)) {
569-
if (grepl("^(?:http(s)?:\\/\\/)?[\\w.-]+(?:\\.[\\w\\.-]+)+[\\w\\-\\._~:/?#[\\]@!\\$&'\\(\\)\\*\\+,;=.]+$",
570-
href,
571-
perl=TRUE) || as_is) {
572-
sprintf("<script src=\"%s\"></script>", href)
573-
}
612+
if (any(grepl("^(?:http(s)?:\\/\\/)?[\\w.-]+(?:\\.[\\w\\.-]+)+[\\w\\-\\._~:/?#[\\]@!\\$&'\\(\\)\\*\\+,;=.]+$",
613+
tagdata,
614+
perl=TRUE)) || as_is) {
615+
if (is.list(tagdata))
616+
glue::glue('<script ', glue::glue_collapse(glue::glue('{attribs}="{tagdata}"'), sep=" "), ' ></script>')
617+
else
618+
glue::glue('<script ', glue::glue('src="{tagdata}"'), ' ></script>')
619+
}
574620
else
575621
stop(sprintf("Invalid URL supplied. Please check the syntax used for this parameter."), call. = FALSE)
576622
} else {
577623
# strip leading slash from href if present
624+
if (is.list(tagdata))
625+
href <- tagdata$src
626+
else
627+
href <- tagdata
578628
href <- sub("^/", "", href)
579629
modified <- as.integer(file.mtime(local_path))
580-
sprintf("<script src=\"%s%s?m=%s\"></script>",
581-
prefix,
582-
href,
583-
modified)
630+
glue::glue('<script src="{prefix}{href}?m={modified}" ></script>')
584631
}
585632
}
586633

man/Dash.Rd

Lines changed: 6 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)