1#' Convert to an HTML document
2#'
3#' Format for converting from R Markdown to an HTML document.
4#'
5#' See the \href{https://bookdown.org/yihui/rmarkdown/html-document.html}{online
6#' documentation} for additional details on using the \code{html_document}
7#' format.
8#'
9#' R Markdown documents can have optional metadata that is used to generate a
10#' document header that includes the title, author, and date. For more details
11#' see the documentation on R Markdown \link[=rmd_metadata]{metadata}.
12#'
13#' R Markdown documents also support citations. You can find more information on
14#' the markdown syntax for citations in the
15#' \href{https://pandoc.org/MANUAL.html#citations}{Bibliographies
16#' and Citations} article in the online documentation.
17#'
18#'@inheritParams output_format
19#'@param toc \code{TRUE} to include a table of contents in the output
20#'@param toc_depth Depth of headers to include in table of contents
21#'@param toc_float \code{TRUE} to float the table of contents to the left of the
22#'  main document content. Rather than \code{TRUE} you may also pass a list of
23#'  options that control the behavior of the floating table of contents. See the
24#'  \emph{Floating Table of Contents} section below for details.
25#'@param number_sections \code{TRUE} to number section headings
26#'@param anchor_sections \code{TRUE} to show section anchors when mouse hovers.
27#'  See \link[rmarkdown:html_document]{Anchor Sections Customization section}.
28#'@param fig_width Default width (in inches) for figures
29#'@param fig_height Default height (in inches) for figures
30#'@param fig_retina Scaling to perform for retina displays (defaults to 2, which
31#'  currently works for all widely used retina displays). Set to \code{NULL} to
32#'  prevent retina scaling. Note that this will always be \code{NULL} when
33#'  \code{keep_md} is specified (this is because \code{fig_retina} relies on
34#'  outputting HTML directly into the markdown document).
35#'@param fig_caption \code{TRUE} to render figures with captions
36#'@param dev Graphics device to use for figure output (defaults to png)
37#'@param code_folding Enable document readers to toggle the display of R code
38#'  chunks. Specify \code{"none"} to display all code chunks (assuming
39#'  they were knit with \code{echo = TRUE}). Specify \code{"hide"} to hide all R
40#'  code chunks by default (users can show hidden code chunks either
41#'  individually or document-wide). Specify \code{"show"} to show all R code
42#'  chunks by default.
43#'@param code_download Embed the Rmd source code within the document and provide
44#'  a link that can be used by readers to download the code.
45#'@param self_contained Produce a standalone HTML file with no external
46#'  dependencies, using data: URIs to incorporate the contents of linked
47#'  scripts, stylesheets, images, and videos. Note that even for self contained
48#'  documents MathJax is still loaded externally (this is necessary because of
49#'  its size).
50#'@param theme One of the following:
51#'  * A [bslib::bs_theme()] object (or a list of [bslib::bs_theme()] argument values)
52#'    * Use this option for custom themes using Bootstrap 4 or 3.
53#'    * In this case, any `.scss`/`.sass` files provided to the `css`
54#'      parameter may utilize the `theme`'s underlying Sass utilities
55#'      (e.g., variables, mixins, etc).
56#'  * `NULL` for no theme (i.e., no [html_dependency_bootstrap()]).
57#'  * A character string specifying a [Bootswatch 3](https://bootswatch.com/3/)
58#'    theme name (for backwards-compatibility).
59#'@param highlight Syntax highlighting style. Supported styles include
60#'  "default", "tango", "pygments", "kate", "monochrome", "espresso", "zenburn",
61#'  "haddock", and "textmate". Pass \code{NULL} to prevent syntax highlighting.
62#'@param mathjax Include mathjax. The "default" option uses an https URL from a
63#'  MathJax CDN. The "local" option uses a local version of MathJax (which is
64#'  copied into the output directory). You can pass an alternate URL or pass
65#'  \code{NULL} to exclude MathJax entirely.
66#'@param section_divs Wrap sections in \code{<div>} tags, and attach identifiers to the
67#'  enclosing \code{<div>} rather than the header itself.
68#'@param template Pandoc template to use for rendering. Pass "default" to use
69#'  the rmarkdown package default template; pass \code{NULL} to use pandoc's
70#'  built-in template; pass a path to use a custom template that you've created.
71#'  Note that if you don't use the "default" template then some features of
72#'  \code{html_document} won't be available (see the Templates section below for
73#'  more details).
74#'@param css CSS and/or Sass files to include. Files with an extension of .sass
75#'  or .scss are compiled to CSS via `sass::sass()`. Also, if `theme` is a
76#'  [bslib::bs_theme()] object, Sass code may reference the relevant Bootstrap
77#'  Sass variables, functions, mixins, etc.
78#'@param includes Named list of additional content to include within the
79#'  document (typically created using the \code{\link{includes}} function).
80#'@param keep_md Keep the markdown file generated by knitting.
81#'@param lib_dir Directory to copy dependent HTML libraries (e.g. jquery,
82#'  bootstrap, etc.) into. By default this will be the name of the document with
83#'  \code{_files} appended to it.
84#'@param md_extensions Markdown extensions to be added or removed from the
85#'  default definition or R Markdown. See the \code{\link{rmarkdown_format}} for
86#'  additional details.
87#'@param pandoc_args Additional command line options to pass to pandoc
88#'@param extra_dependencies,... Additional function arguments to pass to the
89#'  base R Markdown HTML output formatter \code{\link{html_document_base}}
90#'@return R Markdown output format to pass to \code{\link{render}}
91#'
92#'@section Anchor Sections Customization:
93#'  By default, a \samp{#} is used as a minimalist choice, referring to the id selector
94#'  in HTML and CSS. You can easily change that using a css rule in your
95#'  document. For example, to add a \href{https://codepoints.net/U+1F517}{link
96#'  symbol} \if{html}{\out{(&#x1F517;&#xFE0E;)}} instead:
97#'  \preformatted{
98#'  a.anchor-section::before {
99#'    content: '\\01F517\\00FE0E';
100#'  }}
101#'  You can remove \samp{\\00FE0E} to get a more complex link pictogram
102#'  \if{html}{\out{(&#x1F517;)}}.
103#'
104#'  If you prefer an svg icon, you can also use one using for example a direct link or downloading it from
105#'  \url{https://fonts.google.com/icons}.
106#'  \preformatted{
107#'  /* From https://fonts.google.com/icons
108#'     Licence: https://www.apache.org/licenses/LICENSE-2.0.html */
109#'  a.anchor-section::before {
110#'    content: url(https://fonts.gstatic.com/s/i/materialicons/link/v7/24px.svg);
111#'  }}
112#'
113#'  About how to apply custom CSS, see
114#'  \url{https://bookdown.org/yihui/rmarkdown-cookbook/html-css.html}
115#'
116#'@section Navigation Bars:
117#'
118#'  If you have a set of html documents which you'd like to provide a common
119#'  global navigation bar for, you can include a "_navbar.yml" or "_navbar.html"
120#'  file within the same directory as your html document and it will automatically
121#'  be included at the top of the document.
122#'
123#'  The "_navbar.yml" file includes \code{title}, \code{type}, \code{left}, and
124#'  \code{right} fields (to define menu items for the left and right of the navbar
125#'  respectively). Menu items include \code{title} and \code{href} fields. For example:
126#'
127#'  \preformatted{title: "My Website"
128#' type: default
129#' left:
130#'   - text: "Home"
131#'     href: index.html
132#'   - text: "Other"
133#'     href: other.html
134#' right:
135#'   - text: GitHub
136#'     href: https://github.com}
137#'  The \code{type} field is optional and can take the value "default" or "inverse" (which
138#'  provides a different color scheme for the navigation bar).
139#'
140#'  Alternatively, you can include a "_navbar.html" file which is a full HTML definition
141#'  of a bootstrap navigation bar. For a simple example of including a navigation bar see
142#'  \url{https://github.com/rstudio/rmarkdown-website/blob/master/_navbar.html}.
143#'   For additional documentation on creating Bootstrap navigation bars see
144#'  \url{https://getbootstrap.com/docs/4.5/components/navbar/}.
145#'
146#'
147#'@section Floating Table of Contents:
148#'
149#'  You may specify a list of options for the \code{toc_float} parameter which
150#'  control the behavior of the floating table of contents. Options include:
151#'
152#'  \itemize{ \item{\code{collapsed} (defaults to \code{TRUE}) controls whether
153#'  the table of contents appears with only the top-level (H2) headers. When
154#'  collapsed the table of contents is automatically expanded inline when
155#'  necessary.} \item{\code{smooth_scroll} (defaults to \code{TRUE}) controls
156#'  whether page scrolls are animated when table of contents items are navigated
157#'  to via mouse clicks.} \item{\code{print} (defaults to \code{TRUE}) controls
158#'  whether the table of contents appears when user prints out the HTML page.}}
159#'
160#'@section Tabbed Sections:
161#'
162#'  You can organize content using tabs by applying the \code{.tabset} class
163#'  attribute to headers within a document. This will cause all sub-headers of
164#'  the header with the \code{.tabset} attribute to appear within tabs rather
165#'  than as standalone sections. For example:
166#'
167#'  \preformatted{## Quarterly Results {.tabset}
168#'
169#' ### By Product
170#'
171#' ### By Region }
172#'
173#'  You can also specify two additional attributes to control the appearance and
174#'  behavior of the tabs. The \code{.tabset-fade} attributes causes the tabs to
175#'  fade in and out when switching. The \code{.tabset-pills} attribute causes
176#'  the visual appearance of the tabs to be "pill" rather than traditional tabs.
177#'  For example:
178#'
179#'  \preformatted{## Quarterly Results {.tabset .tabset-fade .tabset-pills}}
180#'
181#'@section Templates:
182#'
183#'  You can provide a custom HTML template to be used for rendering. The syntax
184#'  for templates is described in the
185#'  \href{https://pandoc.org/MANUAL.html}{pandoc documentation}. You can also use
186#'  the basic pandoc template by passing \code{template = NULL}.
187#'
188#'  Note however that if you choose not to use the "default" HTML template then
189#'  several aspects of HTML document rendering will behave differently:
190#'
191#'  \itemize{ \item{The \code{theme} parameter does not work (you can still
192#'  provide styles using the \code{css} parameter). } \item{For the
193#'  \code{highlight} parameter, the default highlighting style will resolve to
194#'  "pygments" and the "textmate" highlighting style is not available }
195#'  \item{The \code{toc_float} parameter will not work. } \item{The
196#'  \code{code_folding} parameter will not work. } \item{Tabbed sections (as
197#'  described above) will not work.} \item{Navigation bars (as described above)
198#'  will not work. }\item{MathJax will not work if \code{self_contained} is
199#'  \code{TRUE} (these two options can't be used together in normal pandoc
200#'  templates). } }
201#'
202#'  Due to the above restrictions, you might consider using the \code{includes}
203#'  parameter as an alternative to providing a fully custom template.
204#'
205#' @examples
206#' \dontrun{
207#' library(rmarkdown)
208#'
209#' render("input.Rmd", html_document())
210#'
211#' render("input.Rmd", html_document(toc = TRUE))
212#' }
213#' @md
214#' @export
215html_document <- function(toc = FALSE,
216                          toc_depth = 3,
217                          toc_float = FALSE,
218                          number_sections = FALSE,
219                          anchor_sections = FALSE,
220                          section_divs = TRUE,
221                          fig_width = 7,
222                          fig_height = 5,
223                          fig_retina = 2,
224                          fig_caption = TRUE,
225                          dev = 'png',
226                          df_print = "default",
227                          code_folding = c("none", "show", "hide"),
228                          code_download = FALSE,
229                          self_contained = TRUE,
230                          theme = "default",
231                          highlight = "default",
232                          mathjax = "default",
233                          template = "default",
234                          extra_dependencies = NULL,
235                          css = NULL,
236                          includes = NULL,
237                          keep_md = FALSE,
238                          lib_dir = NULL,
239                          md_extensions = NULL,
240                          pandoc_args = NULL,
241                          ...) {
242
243  # build pandoc args
244  args <- c("--standalone")
245
246  # use section divs
247  if (section_divs)
248    args <- c(args, "--section-divs")
249
250  # table of contents
251  args <- c(args, pandoc_toc_args(toc, toc_depth))
252
253  # makes downstream logic easier to reason about
254  theme <- resolve_theme(theme)
255
256  # toc_float
257  if (toc && !identical(toc_float, FALSE)) {
258
259    # must have a theme
260    if (is.null(theme))
261      stop("You must use a theme when specifying the 'toc_float' option")
262
263    # resolve options
264    toc_float_options <- list(collapsed = TRUE,
265                              smooth_scroll = TRUE,
266                              print = TRUE)
267    if (is.list(toc_float)) {
268      toc_float_options <- merge_lists(toc_float_options, toc_float)
269      toc_float <- TRUE
270    } else if (!isTRUE(toc_float)) {
271      stop("toc_float must be a logical or a list with options")
272    }
273
274    # dependencies
275    extra_dependencies <- append(extra_dependencies,
276                                 list(html_dependency_jquery(),
277                                      html_dependency_jqueryui(),
278                                      html_dependency_tocify()))
279
280    # flag for template
281    args <- c(args, pandoc_variable_arg("toc_float", "1"))
282
283    # selectors
284    selectors <- paste0("h", seq(1, toc_depth), collapse = ",")
285    args <- c(args, pandoc_variable_arg("toc_selectors", selectors))
286
287    # options
288    if (toc_float_options$collapsed)
289      args <- c(args, pandoc_variable_arg("toc_collapsed", "1"))
290    if (toc_float_options$smooth_scroll)
291      args <- c(args, pandoc_variable_arg("toc_smooth_scroll", "1"))
292    if (toc_float_options$print)
293      args <- c(args, pandoc_variable_arg("toc_print", "1"))
294  }
295
296  # template path and assets
297  template_file <- if (identical(template, "default")) {
298    pkg_file("rmd/h/default.html")
299  } else template
300  if (!is.null(template_file))
301    args <- c(args, "--template", pandoc_path_arg(template_file))
302
303  # validate code_folding
304  code_folding <- match.arg(code_folding)
305
306  # navigation dependencies
307  if (!is.null(theme)) {
308    code_menu <- !identical(code_folding, "none") || code_download
309    source_embed <- code_download
310    extra_dependencies <- append(extra_dependencies,
311      list(
312        html_dependency_jquery(),
313        html_dependency_navigation(code_menu = code_menu,
314                                   source_embed = source_embed)
315      )
316    )
317  }
318
319  # highlight
320  args <- c(args, pandoc_html_highlight_args(template, highlight))
321
322  # add highlight.js html_dependency if required
323  extra_dependencies <- append(
324    extra_dependencies,
325    if (identical(template, "default") && is_highlightjs(highlight)) {
326      list(html_dependency_highlightjs(highlight))
327    } else if (!is.null(highlight)) {
328      # for screen-reader accessibility improvement
329      list(html_dependency_accessible_code_block())
330    }
331  )
332
333  # numbered sections
334  if (number_sections)
335    args <- c(args, "--number-sections")
336
337
338  # manage list of exit_actions (backing out changes to knitr options)
339  exit_actions <- list()
340  on_exit <- function() {
341    for (action in exit_actions)
342      try(action())
343  }
344
345  # capture the source code if requested
346  source_code <- NULL
347  source_file <- NULL
348  pre_knit <- function(input, ...) {
349    if (code_download) {
350      source_file <<- basename(input)
351      source_code <<- paste0(
352        '<div id="rmd-source-code">',
353        xfun::base64_encode(input),
354        '</div>')
355    }
356  }
357
358  # pagedtable
359  if (identical(df_print, "paged")) {
360    extra_dependencies <- append(extra_dependencies,
361                                 list(html_dependency_pagedtable()))
362  }
363
364  # anchor-sections
365  if (anchor_sections) {
366    extra_dependencies <- append(extra_dependencies,
367                                 list(html_dependency_anchor_sections()))
368  }
369
370  # pre-processor for arguments that may depend on the name of the
371  # the input file AND which need to inject html dependencies
372  # (otherwise we could just call the pre_processor)
373  post_knit <- function(metadata, input_file, runtime, ...) {
374
375    # extra args
376    args <- c()
377
378    # navbar (requires theme)
379    if (!is.null(theme)) {
380
381      # add navbar to includes if necessary
382      navbar <- file.path(normalize_path(dirname(input_file)), "_navbar.html")
383
384      # if there is no _navbar.html look for a _navbar.yml
385      if (!file.exists(navbar)) {
386        navbar_yaml <- file.path(dirname(navbar), "_navbar.yml")
387        if (file.exists(navbar_yaml))
388          navbar <- navbar_html_from_yaml(navbar_yaml)
389        # if there is no _navbar.yml then look in site config (if we have it)
390        config <- site_config(input_file)
391        if (!is.null(config) && !is.null(config$navbar))
392          navbar <- navbar_html(config$navbar)
393      }
394
395      if (file.exists(navbar)) {
396
397        # include the navbar html
398        includes <- list(before_body = navbar)
399        args <- c(args, includes_to_pandoc_args(includes,
400                                  filter = if (is_shiny_classic(runtime))
401                                    function(x) normalize_path(x, mustWork = FALSE)
402                                  else
403                                    identity))
404
405        # flag indicating we need extra navbar css and js
406        args <- c(args, pandoc_variable_arg("navbar", "1"))
407
408        # navbar icon dependencies
409        iconDeps <- navbar_icon_dependencies(navbar)
410        if (length(iconDeps) > 0)
411          knitr::knit_meta_add(list(iconDeps))
412      }
413    }
414
415    args
416  }
417
418  # pre-processor for arguments that may depend on the name of the
419  # the input file (e.g. ones that need to copy supporting files)
420  pre_processor <- function(metadata, input_file, runtime, knit_meta, files_dir,
421                            output_dir) {
422
423    # use files_dir as lib_dir if not explicitly specified
424    if (is.null(lib_dir))
425      lib_dir <- files_dir
426
427    # extra args
428    args <- c()
429
430    # track whether we have a code menu
431    code_menu <- FALSE
432
433    # code_folding
434    if (code_folding %in% c("show", "hide")) {
435      # must have a theme
436      if (is.null(theme))
437        stop("You must use a theme when specifying the 'code_folding' option")
438      args <- c(args, pandoc_variable_arg("code_folding", code_folding))
439      code_menu <- TRUE
440    }
441
442    # source_embed
443    if (code_download) {
444      if (is.null(theme))
445        stop("You must use a theme when specifying the 'code_download' option")
446      args <- c(args, pandoc_variable_arg("source_embed", source_file))
447      sourceCodeFile <- tempfile(fileext = ".html")
448      write_utf8(source_code, sourceCodeFile)
449      args <- c(args, pandoc_include_args(after_body = sourceCodeFile))
450      code_menu <- TRUE
451    }
452
453    # code menu
454    if (code_menu)
455      args <- c(args, pandoc_variable_arg("code_menu", "1"))
456
457    # content includes (we do this here so that user include-in-header content
458    # goes after dependency generated content). make the paths absolute if
459    # making a Shiny document so we can resolve them even if rendering
460    # elsewhere.
461    args <- c(args, includes_to_pandoc_args(includes,
462                      filter = if (is_shiny_classic(runtime))
463                        function(x) normalize_path(x, mustWork = FALSE)
464                      else
465                        identity))
466
467    # return additional args
468    args
469  }
470
471  # return format
472  output_format(
473    knitr = knitr_options_html(fig_width, fig_height, fig_retina, keep_md, dev),
474    pandoc = pandoc_options(to = "html",
475                            from = from_rmarkdown(fig_caption, md_extensions),
476                            args = args),
477    keep_md = keep_md,
478    clean_supporting = self_contained,
479    df_print = df_print,
480    pre_knit = pre_knit,
481    post_knit = post_knit,
482    pre_processor = pre_processor,
483    on_exit = on_exit,
484    base_format = html_document_base(theme = theme,
485                                     self_contained = self_contained,
486                                     lib_dir = lib_dir, mathjax = mathjax,
487                                     template = template,
488                                     pandoc_args = pandoc_args,
489                                     extra_dependencies = extra_dependencies,
490                                     css = css,
491                                     ...)
492  )
493}
494
495
496#' Knitr options for an HTML output format
497#'
498#' Define knitr options for an R Markdown output format that creates
499#' HTML output.
500#'
501#' @inheritParams html_document
502#' @return An list that can be passed as the \code{knitr} argument of the
503#'   \code{\link{output_format}} function.
504#' @seealso \link{knitr_options}, \link{output_format}
505#' @export
506knitr_options_html <- function(fig_width,
507                               fig_height,
508                               fig_retina,
509                               keep_md,
510                               dev = 'png') {
511
512  opts_chunk <- list(dev = dev,
513                     dpi = 96,
514                     fig.width = fig_width,
515                     fig.height = fig_height,
516                     fig.retina = fig_retina)
517
518  if (keep_md)
519    opts_chunk$fig.retina <- NULL
520
521  knitr_options(opts_chunk = opts_chunk)
522}
523
524# CSS files in inst/rmd/h/bootstrap/css
525themes <- function() {
526  c("default", # keep for backward compatibility reason, changed to 'bootstrap' internally
527    "bootstrap",
528    "cerulean",
529    "cosmo",
530    "darkly",
531    "flatly",
532    "journal",
533    "lumen",
534    "paper",
535    "readable",
536    "sandstone",
537    "simplex",
538    "spacelab",
539    "united",
540    "yeti")
541}
542
543html_highlighters <- function() {
544  c(highlighters(), "textmate")
545}
546
547default_mathjax <- function() {
548  paste0("https://mathjax.rstudio.com/latest/", mathjax_config())
549}
550
551mathjax_config <- function() {
552  "MathJax.js?config=TeX-AMS-MML_HTMLorMML"
553}
554
555
556navbar_html_from_yaml <- function(navbar_yaml) {
557
558  # parse the yaml
559  navbar <- yaml_load_file(navbar_yaml)
560
561  # generate the html
562  navbar_html(navbar)
563}
564
565
566#' Create a navbar HTML file from a navbar definition
567#'
568#' @param navbar Navbar definition
569#' @param links List of navbar links
570#' @return Path to temporary file with navbar definition
571#' @keywords internal
572#' @export
573navbar_html <- function(navbar) {
574
575  # title and type
576  if (is.null(navbar$title)) navbar$title <- ""
577  if (is.null(navbar$type)) navbar$type <- "default"
578
579  # menu entries
580  left <- navbar_links_html(navbar$left)
581  right <- navbar_links_html(navbar$right)
582
583  # build the navigation bar and return it as a temp file
584  template <- file_string(pkg_file("rmd/h/_navbar.html"))
585  navbar_html <- sprintf(template, navbar$type, navbar$title, left, right)
586  as_tmpfile(navbar_html)
587}
588
589#' @keywords internal
590#' @name navbar_html
591#' @export
592navbar_links_html <- function(links) {
593  as.character(navbar_links_tags(links))
594}
595
596navbar_links_tags <- function(links, depth = 0L) {
597
598  if (!is.null(links)) {
599
600    tags <- lapply(links, function(x) {
601
602      if (!is.null(x$menu)) {
603
604        # sub-menu
605        is_submenu <- depth > 0L
606
607        if (is_submenu) {
608          menu_class <- "dropdown-submenu"
609          link_text <- navbar_link_text(x)
610        } else {
611          menu_class <- "dropdown"
612          link_text <- navbar_link_text(x, " ", tags$span(class = "caret"))
613        }
614
615        submenuLinks <- navbar_links_tags(x$menu, depth = depth + 1L)
616
617        tags$li(class = menu_class,
618                tags$a(
619                  href = "#", class = "dropdown-toggle",
620                  `data-toggle` = "dropdown", role = "button",
621                  `aria-expanded` = "false", link_text),
622                tags$ul(class = "dropdown-menu", role = "menu", submenuLinks)
623        )
624
625      } else if (!is.null(x$text) && grepl("^\\s*-{3,}\\s*$", x$text)) {
626
627        # divider
628        tags$li(class = "divider")
629
630      } else if (!is.null(x$text) && is.null(x$href)) {
631
632        # header
633        tags$li(class = "dropdown-header", x$text)
634
635      } else {
636
637        # standard menu item
638        textTags <- navbar_link_text(x)
639        tags$li(tags$a(href = x$href, textTags))
640      }
641    })
642    tagList(tags)
643  } else {
644    tagList()
645  }
646}
647
648navbar_link_text <- function(x, ...) {
649
650  if (!is.null(x$icon)) {
651    # find the iconset
652    split <- strsplit(x$icon, "-")
653    if (length(split[[1]]) > 1)
654      iconset <- split[[1]][[1]]
655    else
656      iconset <- ""
657    # check if a full class is passed for fontawesome = V5
658    # Add fa deprecated fa prefix otherwise = V4 compatibility
659    # https://github.com/rstudio/rmarkdown/issues/1554
660    class = if (grepl("^fa\\w? fa", iconset)) {
661      # Fontawesome 5 - full new prefix + name must be passed
662      # if old fa prefix is passed - keep it for compatibility
663      x$icon
664    } else if (iconset == "fa") {
665      # Fontawesome 4 compatibility - Add deprecated fa prefix
666      paste("fa", x$icon)
667    } else {
668      # Other Icon sets
669      paste(iconset, x$icon)
670    }
671    tagList(tags$span(class = class), " ", x$text, ...)
672  }
673  else
674    tagList(x$text, ...)
675}
676
677