rstudio / htmltools Goto Github PK
View Code? Open in Web Editor NEWTools for HTML generation and output
Home Page: https://rstudio.github.io/htmltools/
Tools for HTML generation and output
Home Page: https://rstudio.github.io/htmltools/
I am having trouble getting the html head tag to be emitted. Other tags seem to work. Example:
> htmltools::tags$body()
<body></body>
> htmltools::tags$head()
> htmltools::tags$title('Test')
<title>Test</title>
> htmltools::tags$head(htmltools::tags$title('Test'))
>
i.e. htmltools::tags$head() emits nothing. Am I doing something wrong? Or is this broken?
I am using the current version of the htmltools package from CRAN, i.e. 0.3.5
Currently passing the result of packageVersion("foo")
as an HTML dependency's version number causes an error at compare time. Consider allowing these by casting them to character.
tag("a", list(HTML("&"), href=HTML("mailto:&")))
gives
<a href="mailto:&">&</a>
when I would expect
<a href="mailto:&">&</a>
NB: this is a problem to obfuscate email addresses using markdown for example.
If an argument to a tag function is NA, then it should be turned into an empty HTML attribute:
div(class = "abc", foo=NA)
#> <div class="abc" foo></div>
However, if there are two other arguments with the same name, then the NA will turn into "NA"
:
div(class = "abc", class = "xyz", foo=NA)
#> <div class="abc xyz" foo="NA"></div>
I am trying to make rCharts
plots easier to use with rmarkdown
. I wrote a simple function that makes use of the configuration file in rCharts
to import dependencies
importChart <- function(chart){
lib = chart$LIB$url
config = yaml::yaml.load_file(file.path(lib, 'config.yml'))[[1]]
htmlDependency(chart$lib, "1.0.1", src = lib,
script = config$jshead, style = config$css
)
}
However, if I try to use attachDependencies
to add this to a test page, only the first script and stylesheet is included. I tried to trace the source of this bug, but the chain of functions went really deep and I wasn't sure where to look.
page = attachDependencies(tags$html('page'), importChart(r2))
html_print(page)
Is this a bug, or am I doing something wrong with how I amusing htmlDependency
?
I could have easily missed an easier solution, but saving a tagList
especially as selfcontained = TRUE
seems difficult. Here is the function I wrote to accomplish this using bits and pieces of htmltools
. Would this be deemed as something worth of htmltools
?
save_tags <- function (tags, file, selfcontained = F, libdir = "./lib")
{
if (is.null(libdir)) {
libdir <- paste(tools::file_path_sans_ext(basename(file)),
"_files", sep = "")
}
htmltools::save_html(tags, file = file, libdir = libdir)
if (selfcontained) {
if (!htmlwidgets:::pandoc_available()) {
stop("Saving a widget with selfcontained = TRUE requires pandoc. For details see:\n",
"https://github.com/rstudio/rmarkdown/blob/master/PANDOC.md")
}
htmlwidgets:::pandoc_self_contained_html(file, file)
unlink(libdir, recursive = TRUE)
}
return(file)
}
I've been developing a module, and I've just noticed that the includeMarkdown()
function will fail if the file is empty. Although this may seem fairly harmless, I have a project in which we develop modules that may include a help file, and the example help.md
file is sometimes empty. If I add just a small amount of text to it, the function works again, and if I remove all text, the function fails.
It'd be nice just to include an empty pair of tags just to make sure that the function stays in tact in this very mundane fail case.
Here is my problem:
I have data loaded from a file encoded in UTF-8 that contains quotes and accents.
I then try to use it as content in an attribute of an HTML tag. But during the rendering of the tag, htmlEscape calls gsub and then when gsub replaces my quotes, the encoding is lost from my string. Not modified, just lost...
Before gsub I have:
text
[1] "Nombre d'observations. Devrait être numérique"
Encoding(text)
[1] "UTF-8"
And after the gsub:
text
[1] "Nombre d'observations. Devrait être numérique"
Encoding(text)
[1] "unknown"
And if I do:
Encoding(text) <- "UTF-8"
text
[1] "Nombre d'observations. Devrait être numérique"
Everything works fine again!
My workaround for the moment is quite easy. I just save the encoding before the gsub loop and then reapply it at the end and everything seems ok!
The only problem is I seem to have to do it in htmlEscape because the final encoding of the tag rendering is UTF-8 and yet the error subsists. But htmlEscape is buried so deep in the call stack that the only way I found to fix it quickly is by replacing htmlEscape with my modified version with assignInNamespace, which is not really nice it seems.
I don't know if there are there other ways around this problem, but I will gladly take any other solution that doesn't involve ugly hacking!
Thanks a lot!
library(htmltools)
dep <- htmlDependency(
name = "foo",
version = "0.0.1",
script = "foo.js",
src = list(file = ""),
package = "htmltools",
all_files = FALSE
)
copyDependencyToDir(dep, "bar")
Error in dirname(to) : a character vector argument expected
It'd be useful if the error message said something to the effect of: Can't copy 'foo.js' since it doesn't exist
This is documented in rstudio/shiny#568, but essentially utils::URLencode
accepts only one argument.
URLencode( c("a", "b") )
[1] "a"
You probably want to wrap encodeFunc
with an sapply in teh definition for renderDependencies
.
If htmlDependency()
is called in a package namespace with a system.file()
argument, this can lead to a subtle problem that will be visible only after a the binary package is built and distributed on CRAN.
For example, in shinybootstrap2, there is this code:
dataTableDependency <- list(
htmlDependency(
"datatables", "1.10.2",
c(file = system.file("www/datatables", package = "shinybootstrap2")),
script = "js/jquery.dataTables.min.js"
),
htmlDependency(
"datatables-bootstrap", "1.10.2",
c(file = system.file("www/datatables", package = "shinybootstrap2")),
stylesheet = c("css/dataTables.bootstrap.css", "css/dataTables.extra.css"),
script = "js/dataTables.bootstrap.js"
)
)
This works fine when the package is built and tested on the same machine. However, if the package is built on one machine and then used on another (as is the case with CRAN binary packages), then this will fail -- the dependency will point to the wrong directory on the host.
It fails because system.file()
is called at build-time, and the result is stored in the variable dataTableDependency
and saved in the binary package. When someone installs the binary package on their machine, the path isn't updated to their path -- it still refers to a path on the machine that built the binaries.
If, on the other hand, htmlDependency()
is called from a function at run-time, everything will work fine.
We've also run into this problem with ggvis, and fixed it by converting the variable to a function: rstudio/ggvis@ac65f35
Note: It just so happens that inside of Shiny proper, you can call htmlDependency()
and store the results, because Shiny's dependencies use relative paths, without system.file()
.
This may sound a bit drastic, but I think it would be a good idea have htmlDependency()
check if (A) system.file()
is called in any of its arguments, and (B) the parent frame is a package namespace. If both of these are true, give a warning or message. I think it would be helpful because otherwise, developers will run into this problem only after their package seems OK and is on CRAN -- and then they'll have a really hard time debugging it, and after they fix it, they'll have to resubmit to CRAN. (This was very confusing for us the first time we saw it, in ggvis, and it was still confusing when we saw it again in shinybootstrap2.)
One more update: I just checked, and shinydashboard also has this problem. :( And as with the other two cases, it would only have been found after sending the package to CRAN.
as.character should return the tag as a character. but it doesn't
tags$b("City")
<b>City</b>
as.character(tags$b("City"))
<b>City</b>
htmltools v0.2.6
RRO v 3.2.1
Windows 8.1
The idea would be to allow external CSV/JSON files to be copied to the temp directory in which the html
file is generated so that the page can make use of it. This behavior is very beneficial especially when you are reading large geojson
files and want to keep the file external to your html.
Joe,
I tried to pass "A\nB" to p() and found that \n does not have the desired effect in the rendered HTML page even though the generated HTML file had
A B
Wouldn't it be necessary to "escape" \n by
? I certainly can do p(HTML("A
B")), but p("A\nB") looks more intuitive. What do you think?
Sincerely,
Junghoon Lee
This piece of code
library(mapview)
library(htmlwidgets)
m <- mapview(breweries91)@map
# > class(m)
# [1] "leaflet" "htmlwidget"
saveWidget(m, file = "img/mapshot.html")
throws the following error:
Error in normalizePath(path.expand(path), winslash, mustWork) :
path[1]="img": The system cannot find the file specified
Such an undesirable behavior has been reported previously (e.g., https://bugs.r-project.org/bugzilla3/show_bug.cgi?id=16369). However, after examining the source code, I found that this issue could simply be solved (at least on my machine) by replacing line 83 in html_print.R with
dep <- makeDependencyRelative(dep, getwd(), FALSE)
I.e., specifying the working directory as absolute rather than relative path prevents normalizePath
from failing. Here is the output of sessionInfo()
.
R version 3.3.0 Patched (2016-05-03 r70575)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1locale:
[1] LC_COLLATE=German_Germany.1252 LC_CTYPE=German_Germany.1252 LC_MONETARY=German_Germany.1252
[4] LC_NUMERIC=C LC_TIME=German_Germany.1252attached base packages:
[1] stats graphics grDevices utils datasets methods baseother attached packages:
[1] webshot_0.3.0.9000 gimms_0.5.1 raster_2.5-2 rgdal_1.1-8 sp_1.2-3
[6] mapview_1.0.22 leaflet_1.0.1loaded via a namespace (and not attached):
[1] Rcpp_0.12.4 RColorBrewer_1.1-2 plyr_1.8.3 base64enc_0.1-3 R.methodsS3_1.7.1
[6] R.utils_2.3.0 viridis_0.3.4 iterators_1.0.8 tools_3.3.0 gdalUtils_2.0.1.7
[11] boot_1.3-18 digest_0.6.9 jsonlite_0.9.19 gtable_0.2.0 satellite_0.2.0
[16] memoise_1.0.0 lattice_0.20-33 png_0.1-7 foreach_1.4.3 yaml_2.1.13
[21] parallel_3.3.0 Kendall_2.2 zyp_0.10-1 gridExtra_2.2.1 withr_1.0.1
[26] knitr_1.12.3 htmlwidgets_0.6 rgeos_0.3-19 devtools_1.11.1 stats4_3.3.0
[31] grid_3.3.0 latticeExtra_0.6-28 ggplot2_2.1.0 magrittr_1.5 scales_0.4.0
[36] codetools_0.2-14 Orcs_1.0.3 htmltools_0.3.5 colorspace_1.2-6 munsell_0.4.3
[41] doParallel_1.0.10 R.oo_1.20.0
Hi,
I'm generating a plotly
figure which I save as an html
file:
p <- plot_ly(z = volcano, type = "heatmap")
htmlwidgets::saveWidget(pi,paste0("p.html"))
And then, from an rmarkdown
code, I'd like to embed p.html
.
I thought knit_print.html
can be used for that, e.g. rmarkdown
code chunk:
htmltools::knit_print.html("p.html")
But that doesn't work - it only prints the text "p.html" in the report.
I've also used htmltools::includeHTML
:
htmltools::includeHTML("p.html")
While this does work, when I have other code chunks that embed other graphics (e.g., png figures embedded using knitr::include_graphics
), the result is that p.html
takes over the entire report and the png
s cannot be seen.
So, any idea how to embed plotly
html
pages with non html
(e.g. png
) graphics?
One more related question:
Suppose I generate several plotly
html
figures, e.g. using this code:
for(i in 1:3){
pi <- plot_ly(z = volcano, type = "heatmap")
htmlwidgets::saveWidget(pi,paste0("p.",i,".html"))
}
And I want to embed them in an rmarkdown
code. How do I loop over them and embed them?
I know that if I'd generated them within the rmarkdown
code, I'd use tagList
like in this code:
plot.list <- vector(mode="list",3)
for(i in 1:3) plot.list[[i]] <- plot_ly(z = volcano, type = "heatmap")
htmltools::tagList(plot.list)
So is there something equivalent for html
plots generated and saved externally?
When I render this file, an extra "div form-group shiny-input-container" appears in front of the label of the second slider. This seems to be a side effect of as.tags
not passing on the class shiny.tag
The included as.tags.shiny.tag
functions seems to fix it, but the function is a bit of a hack.
This comes up in real life when I eval and parse code from a shinyAce editor then feed it into as.tags
---
runtime: shiny
---
```{r}
# Works fine
renderUI({
sliderInput("s1", "Slide Me", min = 0, max = 10, val = 5)
})
# Odd label
renderUI({
htmltools::as.tags(sliderInput("s1", "Slide Me", min = 0, max = 10, val = 5))
})
```
```{r eval = FALSE}
# eval = FALSE
# But works again
as.tags.shiny.tag <- function(...) {
structure(htmltools:::as.tags.default(...), class = "shiny.tag")
}
renderUI({
htmltools::as.tags(sliderInput("s1", "Slide Me", min = 0, max = 10, val = 5))
})
```
Should print.htmlwidget
return the output of htmltools::html_print
instead of the passed in x
.
so simply.
html_print(htmltools::as.tags(x, standalone=TRUE), viewer = if (view) viewerFunc))
instead of
html_print(htmltools::as.tags(x, standalone=TRUE), viewer = if (view) viewerFunc)
# return value
invisible(x)
htmltools::html_print
return the saved HTML path invisibly.
Getting back the same widget is not really helpful, but getting back the HTML file path where the widget is stored can be very helpful. e.g.
saved_widget_html <- print(widget, view=NULL)
# Now use the save_widget_html path to do something else.
Same for print.suppress_viewer
.
I am trying to add HTML buttons to a DT using dplyr, but I seem to have run into an edgecase.
library(dplyr)
library(htmltools)
# obviously works
data.frame(x = c("A","B","C")) %>%
mutate(row = row_number())
# doesn't work
data.frame(x = c("A","B","C")) %>%
mutate(button = HTML(as.character(tags$button(id = paste0("btn",row_number())))))
# also doesn't work
data.frame(x = c("A","B","C")) %>%
mutate(row = row_number()) %>%
mutate(button = HTML(as.character(tags$button(id = paste0("btn", row)))))
Weirdly it seems a whole vector of row numbers is getting passed to paste0
so each button has a vector of ids so it spits out a warning and subsets to the first yielding a table with buttons all having the same id.
Kind Regards
I'm trying to build htmltools on MacOS, but the build fails with these messages:
** testing if installed package can be loaded
Error: package or namespace load failed for ‘htmltools’ in dyn.load(file, DLLpath = DLLpath, ...):
unable to load shared object '/Library/Frameworks/R.framework/Versions/3.4/Resources/library/htmltools/libs/htmltools.so':
dlopen(/Library/Frameworks/R.framework/Versions/3.4/Resources/library/htmltools/libs/htmltools.so, 6): Symbol not found: _htmltools_template_dfa
Referenced from: /Library/Frameworks/R.framework/Versions/3.4/Resources/library/htmltools/libs/htmltools.so
Expected in: flat namespace in /Library/Frameworks/R.framework/Versions/3.4/Resources/library/htmltools/libs/htmltools.so
Error: loading failed
Execution halted
ERROR: loading failed
* removing ‘/Library/Frameworks/R.framework/Versions/3.4/Resources/library/htmltools’
The missing symbol is one produced automatically by Rcpp, so I've tried updating Rcpp, deleting the automatically generated files and regenerating them, etc., all with no improvement. Is this a problem in htmltools, or on my system (which I've recently updated)?
The list element that is meant to hold the name of the directory to find "the goods" in seems to be in flux and the object that is generated within htmltools
is not valid as far as rmarkdown
is concerned.
htmltools::htmlDependency
puts this in a list element named src
and it seems that rmarkdown::validate_html_dependency
expects this to be in a list element named path
.
Furthermore, src
is flagged as an invalid_field
at the tail end rmarkdown::validate_html_dependency
.
I'm running into this bug because I'm trying to get an rmdexmaples::datatable into an rmarkdown report.
checking DESCRIPTION meta-information ... NOTE
Malformed Description field: should contain one or more complete sentences.
checking dependencies in R code ... NOTE
'library' or 'require' call to ‘markdown’ in package code.
Please use :: or requireNamespace() instead.
See section 'Suggested packages' in the 'Writing R Extensions' manual.
It would be nice, if there is a way to insert JS&CSS dependencies towards the end of the body
tag.
Reasoning:
Putting your script tags at the end of the body tag, after all of the page's contents, means your entire page will begin displaying as soon as possible to give the user something to look at - and then your scripts will download and make everything work.
High priority for me.
Thanks.
Having code like this :
<li class="nav-item">
<a href="#tab-3402-1" class="nav-link active" data-toggle="tab" data-value="Table" role="tab">Table</a>
</li>
I would like to have a method something like this:
deleteTags(tagObject, tag = "li", class= "nav-item")
which would delete
<li class="nav-item"> </li>
code from the above. Resulting into standalone:
<a href="#tab-3402-1" class="nav-link active" data-toggle="tab" data-value="Table" role="tab">Table</a>
As described in my StackOverflow question, if in a Shiny app you write something like
p('This is my ', a(href = 'https://stackoverflow.com/', 'favorite link ever'), '!')
because of the way line feeds and spaces are rendered between each of the child elements the resulting HTML is
<p>
This is my
<a href="https://stackoverflow.com/">favorite link ever</a>
!
</p>
Which looks like this (note the space before the exclamation mark)
This is my favorite link ever !
I think I've correctly tracked this down to this section of code:
Line 420 in 02678ee
Maybe the "special case" block could be expanded to deal with this? It feels like the renderer is too eager to add line feeds and indents, and there are more cases where this is not necessary/wanted.
I know this can be worked around by building explicit HTML (say with HTML(paste0(...))
), but since my year-old SO question still gets an occasional upvote I figured I should write something up here.
Related issue: #80
Currently, boolean attributes (see this link) may be passed to a tag using the empty string syntax.
library(htmltools)
tags$button(type = "button", disable = "")
Per https://html.spec.whatwg.org/#boolean-attributes, this works.
However, boolean attributes cannot be used without use of the empty string.
library(htmltools)
tagAppendAttributes(
tags$button(type = "button"),
"disable"
)
(currently throws an error because the attribute is not named)
This is not a bug, the empty string syntax works for now, simply an enhancement.
See rstudio/shiny#1395.
We also need to test this when the HEAD contains characters that are in Windows-1252 but not UTF-8, like accented latin characters.
For example:
> div("foo", "bar")
<div>
foo
bar
</div>
It would be good to be able to do something like one of the following:
div(.nospace = TRUE, "foo", "bar")
div("foo", nospace(), "bar")
nospace(div("foo", "bar"))
In use of htmltools::htmlDependency() for CDNs, it would allow for SRI checking (which ensures resources hosted on third-party servers have not been tampered with), considered a best practice.
Example from jQuery:
<script
src="https://code.jquery.com/jquery-1.12.4.min.js"
integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="
crossorigin="anonymous"></script>
References:
Currently we need to do something like this to add a dependency:
attachDependency(
div(),
htmlDependency(...)
)
It would be nice to be able to do this:
tagList(
div(),
htmlDependency(...)
)
This would make it simpler to add dependencies inline.
It looks like this is by design. https://github.com/rstudio/htmltools/blob/master/inst/tests/test-tags.r#L64
Are you willing to reconsider? I'm playing with a library that uses JSON in data-*
attributes, and the quotes unavoidably get escaped despite wrapping them in HTML()
. I would think that honoring opt-in HTML-tagging of an attribute would be safe/reasonable behavior, but perhaps there's another side to the story I'm not considering.
When knitting an Rmd with a datatable, was failing with:
Error in enc2utf8(text) argument is not a character vector
I tried include = FALSE
and echo = FALSE
on the DT::datatable
chunk, but still could not knit the document.
Based on the traceback (collapsed, below) it looks like it's failing on htmlEscape(dep$meta)
.
Possibly related to:
Line 36 in 9e219b8
paste("<meta name="", htmlEscape(names(dep$meta)), "" content="",
htmlEscape(dep$meta), "" />", sep = "")
renderDependencies(dependencies, "file", encodeFunc = identity,
hrefFilter = function(path) {
html_reference_path(path, lib_dir, output_dir)
})
html_dependencies_as_string(dependencies, NULL, NULL)
as_tmpfile(html_dependencies_as_string(dependencies, NULL, NULL))
pandoc_html_extras_args(extras, self_contained, lib_dir, output_dir)
base(...)
output_format$pre_processor(yaml_front_matter, utf8_input, runtime, knit_meta, files_dir, output_dir)
rmarkdown::render(here::here("inst", "pkgreporting.Rmd"))
I was able to fix this by downgrading to the CRAN version of htmltools.
pandoc version 2.2
rmarkdown at rstudio/markdown@5abbfae
Just let me know if you need more info, or if this is the wrong repo! 😳
In 2013, Joe suggested that there would be a better solution than using HTML()
forthcoming, to avoid the problem. It seems to have been forgotten about, so I have added it to your tracker.
I wrote a function that converts raw html text to a tagList object. i found that when i try to use tagLists with the example below I get a weird result. The final output is wrapped in a <pre>
chunk.
htmlIn<-print(xtable::xtable(mtcars),type = 'html',print.results = F)
tagL<-html2tagList(htmlIn)
fileGood='testGood.html'
fileBad='testBad.html'
htmltools::save_html(tagL,file=fileGood)
htmlwidgets:::pandoc_self_contained_html(fileGood, fileBad)
This happens because the htmltools:::print.shiny.tag.list
prints by default an indented output and when it gets rendered by markdown it is assumed to be in a pre chunk. is there a way to have it print inline?
<table border="1">
<tr>
<th></th>
<th>mpg</th>
<th>cyl</th>
<th>disp</th>
<th>hp</th>
<th>drat</th>
<th>wt</th>
<th>qsec</th>
<th>vs</th>
<th>am</th>
<th>gear</th>
<th>carb</th>
</tr>
<tr>
<td align="right">Mazda RX4</td>
<td align="right">21.00</td>
<td align="right">6.00</td>
<td align="right">160.00</td>
<td align="right">110.00</td>
<td align="right">3.90</td>
<td align="right">2.62</td>
<td align="right">16.46</td>
<td align="right">0.00</td>
<td align="right">1.00</td>
<td align="right">4.00</td>
<td align="right">4.00</td>
</tr>
<tr>
<td align="right">Mazda RX4 Wag</td>
<td align="right">21.00</td>
<td align="right">6.00</td>
<td align="right">160.00</td>
<td align="right">110.00</td>
<td align="right">3.90</td>
<td align="right">2.88</td>
<td align="right">17.02</td>
<td align="right">0.00</td>
<td align="right">1.00</td>
<td align="right">4.00</td>
<td align="right">4.00</td>
</tr>
<tr>
<td align="right">Datsun 710</td>
<td align="right">22.80</td>
<td align="right">4.00</td>
<td align="right">108.00</td>
<td align="right">93.00</td>
<td align="right">3.85</td>
<td align="right">2.32</td>
<td align="right">18.61</td>
<td align="right">1.00</td>
<td align="right">1.00</td>
<td align="right">4.00</td>
<td align="right">1.00</td>
</tr>
<tr>
<td align="right">Hornet 4 Drive</td>
<td align="right">21.40</td>
<td align="right">6.00</td>
<td align="right">258.00</td>
<td align="right">110.00</td>
<td align="right">3.08</td>
<td align="right">3.21</td>
<td align="right">19.44</td>
<td align="right">1.00</td>
<td align="right">0.00</td>
<td align="right">3.00</td>
<td align="right">1.00</td>
</tr>
<tr>
<td align="right">Hornet Sportabout</td>
<td align="right">18.70</td>
<td align="right">8.00</td>
<td align="right">360.00</td>
<td align="right">175.00</td>
<td align="right">3.15</td>
<td align="right">3.44</td>
<td align="right">17.02</td>
<td align="right">0.00</td>
<td align="right">0.00</td>
<td align="right">3.00</td>
<td align="right">2.00</td>
</tr>
<tr>
<td align="right">Valiant</td>
<td align="right">18.10</td>
<td align="right">6.00</td>
<td align="right">225.00</td>
<td align="right">105.00</td>
<td align="right">2.76</td>
<td align="right">3.46</td>
<td align="right">20.22</td>
<td align="right">1.00</td>
<td align="right">0.00</td>
<td align="right">3.00</td>
<td align="right">1.00</td>
</tr>
</table>
For example:
div(foo=character(0), "text")
# Error in if (!is.na(attribValue)) { : argument is of length zero
I think it should just drop the attribute, the same as if it were NULL
.
https://github.com/rstudio/htmltools/blob/master/R/html_print.R#L89
and please make it customizable e.g. lang="cs", lang="de", lang="lu" so that shiny
can take advantage of it.
BIG THANKS
Several releases have been made to CRAN, but none of them have been tagged here. This makes it difficult to find the exact commit from which any release originated.
Currently, the content of tags$script()
needs to be wrapped with HTML()
in order to not be escaped. But there's no reason (that I can think of) that the content should be escaped, and it just causes confusion with users.
I realize that this is a departure from how all other tag functions work, but it's also true that the <script>
tag is different from other tags.
This issue is relevant for anyone hoping to use htmlDependency()
with (query) parameters (e.g. MathJax). There doesn't seem to be a good way to create this class of dependency so that it gets rendered correctly in various contexts, for example:
library(htmltools)
dep <- htmlDependency(
name = "mathjax",
version = "2.7.4",
src = c(
href = "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4"
),
script = "MathJax.js?config=TeX-AMS-MML_HTMLorMML"
)
renderDependencies(list(dep), "href")
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js%3Fconfig%3DTeX-AMS-MML_HTMLorMML"></script>
You can set encodeFunc = identity
to render this properly...
renderDependencies(list(dep), "href", encodeFunc = identity)
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
...but the problem is that several "higher-level" functions (e.g. htmltools::save_html()
, htmltools::renderDocument()
, and htmlwidgets:::pandoc_save_markdown()
) call renderDependencies()
without a way to set the encodeFunc
argument.
Make it possible to "escape" urlEncodePath
by using a special class, like "AsIs"
urlEncodePath <- function(x) {
if (inherits(x, "AsIs")) return(x)
vURLEncode <- Vectorize(URLencode, USE.NAMES = FALSE)
gsub("%2[Ff]", "/", vURLEncode(x, TRUE))
}
Then you could do:
htmlDependency(
...,
script = I("MathJax.js?config=TeX-AMS-MML_HTMLorMML")
)
Add a query
argument to htmlDependency()
which takes a named list so that
dep <- htmlDependency(
name = "mathjax",
version = "2.7.4",
src = c(
href = "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4"
),
script = "MathJax.js",
config = list(config = "TeX-AMS-MML_HTMLorMML")
)
renderDependencies(list(dep), "href")
would generate
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
For example:
htmlTemplate(text_= "{{ 1+1 }}")
# Error in htmlTemplate(text_ = "{{ 1+1 }}") :
# Mismatched {{ and }} in HTML template.
htmlTemplate(text_= " {{ 1+1 }}")
# Error in FUN(X[[i]], ...) : Mismatched {{ and }} in HTML template.
htmlTemplate(text_= "{{ 1+1 }} ")
# Error in htmlTemplate(text_ = "{{ 1+1 }} ") :
# Mismatched {{ and }} in HTML template.
htmlTemplate(text_= " {{ 1+1 }} ")
# [1] " \n2\n "
Consider the following example.
library(htmltools)
template <- "
<div>
<span>Hello</span>
<span>{{ user }}</span>
</div>
"
htmlTemplate(text_ = template, user = 'Jane Doe')
It renders as shown below
<div>
<span>Hello</span>
<span>
Jane Doe
</span>
</div>
I would have expected htmlTemplate
to respect the indentation and instead render
<div>
<span>Hello</span>
<span>Jane Doe</span>
</div>
It would be useful if renderDependencies()
annotated the injected <script>
/ <link>
tags with data attributes describing the source of each dependency, e.g.
<script
data-name="htmlwidgets"
data-version="0.6"
data-script="htmlwidgets.js"
data-stylesheet=""
src="/path/to/R/library/htmlwidgets/www/htmlwidgets.js"></script>
This would make it possible to recover the source of a dependency after e.g. rmarkdown::render()
is done with the document.
Not sure there is really anything to do about this, but I thought I would post an issue just in case someone else runs into this problem.
Hmisc:::print.html
conflicts with htmltools:::print.html
, and the error I get when doing something like browsable(HTML(...an object of class html...))
is
Error in paste(browser, object, if (.Platform$OS.type == "unix") "&") :
cannot coerce type 'closure' to vector of type 'character'
This error traces to Hmisc
line.
I'll cross-post and refer back to this issue, and then I'll close.
Also probably should check with latest relevant specs to make sure we're not missing any new tags.
this has been migrated from rstudio/shiny#1936.
I'll do a PR sometime soon, as suggested by @jcheng5.
I'm so used to writing in basic markdown (emph, bold, pre
etc.), I can't get myself to write, say shiny::tags$em("foo")
.
Maybe others are feeling the same.
I build myself a simple wrapper to be able to easily write markdown:
#' @title Convert markdown to html
#'
#' @param text A character vector to be converted to markdown.
#'
#' @param HTML A logical flag, indicating whether the result should additionally be wrapped in shiny::HTML().
#'
#' @noRd
md <- function(text, HTML = TRUE) {
res <- markdown::renderMarkdown(
file = NULL,
output = NULL,
text = text
)
if (HTML) {
res <- shiny::HTML(text = res)
}
return(res)
}
which can be used wherever shiny expects HTML.
Now I can write something like:
fileInput(
inputId = "rdata",
label = md("Upload a `*.rdata` file created by *pensieve*."),
)
which makes life a little easier.
Is there any interest in supporting this directly in shiny? I'm guessing an md()
function might be an alternative to / modelled on the existing HTML()
.
If there's interest, I'd be happy to write up a PR.
Just to be sure, what this isn't:
shiny::includeMarkdown()
does that already,So that a separate template file isn't needed.
When exposing a webfont as an html dependency, you need to include a css file, and a handful of web font files. There's currently no way to select only specified files out of the src/
that aren't scripts, stylesheets, or attachments.
For example,
htmlDependency( name="foo", version="1.0", src=c(href="https://foo.io"), import="foo.html" )
would give: <link rel="import" href="https://foo.io/foo.html></link>
in <head>...</head>
. Is there a way to do this already?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.