\nbar")
# tags with children ------------------------------------------------
x <- div(a1.1, div("foo"), "bar")
expect_identical(findDependencies(x), list(a1.1))
expect_identical(as.character(renderTags(x)$html),
"
")
# Passing normal lists to tagLists and tag functions ---------------
x <- tagList(list(a1.1, div("foo")), "bar")
expect_identical(findDependencies(x), list(a1.1))
x <- div(list(a1.1, div("foo")), "bar")
expect_identical(findDependencies(x), list(a1.1))
})
test_that("Modifying children using dependencies", {
a1.1 <- htmlDependency("a", "1.1", c(href="/"))
a1.2 <- htmlDependency("a", "1.2", c(href="/"))
x <- tagAppendChild(div(a1.1), a1.2)
expect_identical(findDependencies(x), list(a1.1, a1.2))
x <- tagAppendChild(div(a1.1), list(a1.2))
expect_identical(findDependencies(x), list(a1.1, a1.2))
x <- tagAppendChildren(div(), a1.1, list(a1.2))
expect_identical(findDependencies(x), list(a1.1, a1.2))
x <- tagSetChildren(div("foo", a1.1), a1.2)
expect_identical(findDependencies(x), list(a1.2))
})
htmltools/tests/testthat/test-template.R 0000644 0001751 0000144 00000017256 13100230764 020241 0 ustar hornik users context("templates")
# Searches for an html dependency of format name[version], as in "d3[3.5.10]",
# within the html-dependencies script tag
findDep <- function(x, name, version) {
deps <- sub(
'.*.*',
"\\1",
x
)
grepl(paste0(name, "[", version, "]"), deps, fixed = TRUE)
}
test_that("Code blocks are evaluated and rendered correctly", {
template <- htmlTemplate("template-document.html",
x = div(class = "foo", "bar")
)
html <- renderDocument(template)
expect_true(grepl('
bar
', html))
# With text_ argument
template <- htmlTemplate(text_ = "a {{ foo + 1 }} b", foo = 10)
expect_identical(as.character(as.character(template)), "a \n11\n b")
# Make char vectors are pasted together
template <- htmlTemplate(text_ = c("a", "{{ foo + 1 }} b"), foo = 10)
expect_identical(as.character(as.character(template)), "a\n\n11\n b")
})
test_that("UTF-8 characters in templates", {
template <- htmlTemplate("template-document.html", x = "")
html <- renderDocument(template)
# Create the string 'Δ★😎', making sure it's UTF-8 encoded on all platforms.
# These characters are 2, 3, and 4 bytes long, respectively.
pat <- rawToChar(as.raw(c(0xce, 0x94, 0xe2, 0x98, 0x85, 0xf0, 0x9f, 0x98, 0x8e)))
Encoding(pat) <- "UTF-8"
expect_true(grepl(pat, html))
# If template is passed text_ argument, make sure it's converted from native
# to UTF-8.
latin1_str <- rawToChar(as.raw(0xFF))
Encoding(latin1_str) <- "latin1"
text <- as.character(htmlTemplate(text_ = latin1_str))
expect_identical(charToRaw(text), as.raw(c(0xc3, 0xbf)))
})
test_that("UTF-8 characters in template head but not body", {
# On Windows, a string with "中文" will automatically be marked as UTF-8.
ui <- tagList(
tags$head(tags$script("alert('中文')")),
"test"
)
html <- htmlTemplate("template-basic.html", body = ui)
res <- renderDocument(html)
expect_identical(Encoding(res), "UTF-8")
expect_true(grepl("中文", res, fixed = TRUE))
# On Windows, a string with "á" will automatically be marked as latin1.
ui <- tagList(
tags$head(tags$script("alert('á')")),
"test"
)
html <- htmlTemplate("template-basic.html", body = ui)
res <- renderDocument(html)
expect_identical(Encoding(res), "UTF-8")
expect_true(grepl("á", res, fixed = TRUE))
})
test_that("Dependencies are added properly", {
dep <- htmlDependency("d3", "3.5.10", c(href="shared"), script = "d3.js")
# Add dependency by inserting a tag with a dependency
template <- htmlTemplate("template-document.html",
x = attachDependencies(div(), dep)
)
html <- renderDocument(template)
expect_true(findDep(html, "d3", "3.5.10"))
expect_true(grepl('', html, fixed = TRUE))
# Add dependency via a renderDocument
template <- htmlTemplate("template-document.html", x = "")
html <- renderDocument(template, dep)
expect_true(findDep(html, "d3", "3.5.10"))
expect_true(grepl('', html, fixed = TRUE))
})
test_that("Dependencies can be suppressed", {
# The template includes suppressDependencies("jquery"), so we shouldn't see
# this dependency in the final output.
dep <- htmlDependency("jquery", "1.11.3", c(href="shared"), script = "jquery.js")
# Add dependency by inserting a tag with a dependency
template <- htmlTemplate("template-document.html",
x = attachDependencies(div(), dep)
)
html <- renderDocument(template)
expect_true(findDep(html, "jquery", "9999"))
expect_false(grepl('",
sep = ""
))
}
if (length(dep$attachment) > 0) {
if (is.null(names(dep$attachment)))
names(dep$attachment) <- as.character(1:length(dep$attachment))
html <- c(html,
sprintf("",
htmlEscape(dep$name),
htmlEscape(names(dep$attachment)),
htmlEscape(hrefFilter(file.path(srcpath, encodeFunc(dep$attachment))))
)
)
}
# add raw head content
html <- c(html, dep$head)
}
HTML(paste(html, collapse = "\n"))
}
# html_dependencies_as_character(list(
# htmlDependency("foo", "1.0",
# c(href="http://foo.com/bar%20baz/"),
# stylesheet="x y z.css"
# )
# ))
#
# html_dependencies_as_character(list(
# htmlDependency("foo", "1.0",
# c(href="http://foo.com/bar%20baz"),
# stylesheet="x y z.css"
# )
# ))
#
# html_dependencies_as_character(list(
# htmlDependency("foo", "1.0",
# "foo bar/baz",
# stylesheet="x y z.css"
# )
# ))
#
# html_dependencies_as_character(list(
# htmlDependency("foo", "1.0",
# "foo bar/baz/",
# stylesheet="x y z.css"
# )
# ))
#
htmltools/R/tags.R 0000644 0001751 0000144 00000136336 13100230764 013607 0 ustar hornik users #' @import utils digest
NULL
# Like base::paste, but converts all string args to UTF-8 first.
paste8 <- function(..., sep = " ", collapse = NULL) {
args <- c(
lapply(list(...), enc2utf8),
list(
sep = if (is.null(sep)) sep else enc2utf8(sep),
collapse = if (is.null(collapse)) collapse else enc2utf8(collapse)
)
)
do.call(paste, args)
}
# Reusable function for registering a set of methods with S3 manually. The
# methods argument is a list of character vectors, each of which has the form
# c(package, genname, class).
registerMethods <- function(methods) {
lapply(methods, function(method) {
pkg <- method[[1]]
generic <- method[[2]]
class <- method[[3]]
func <- get(paste(generic, class, sep="."))
if (pkg %in% loadedNamespaces()) {
registerS3method(generic, class, func, envir = asNamespace(pkg))
}
setHook(
packageEvent(pkg, "onLoad"),
function(...) {
registerS3method(generic, class, func, envir = asNamespace(pkg))
}
)
})
}
.onLoad <- function(...) {
# htmltools provides methods for knitr::knit_print, but knitr isn't a Depends or
# Imports of htmltools, only an Enhances. Therefore, the NAMESPACE file has to
# declare it as an export, not an S3method. That means that R will only know to
# use our methods if htmltools is actually attached, i.e., you have to use
# library(htmltools) in a knitr document or else you'll get escaped HTML in your
# document. This code snippet manually registers our methods with S3 once both
# htmltools and knitr are loaded.
registerMethods(list(
# c(package, genname, class)
c("knitr", "knit_print", "html"),
c("knitr", "knit_print", "shiny.tag"),
c("knitr", "knit_print", "shiny.tag.list")
))
}
depListToNamedDepList <- function(dependencies) {
if (inherits(dependencies, "html_dependency"))
dependencies <- list(dependencies)
if (is.null(names(dependencies))) {
names(dependencies) <- sapply(dependencies, `[[`, "name")
}
return(dependencies)
}
#' Resolve a list of dependencies
#'
#' Given a list of dependencies, removes any redundant dependencies (based on
#' name equality). If multiple versions of a dependency are found, the copy with
#' the latest version number is used.
#'
#' @param dependencies A list of \code{\link{htmlDependency}} objects.
#' @param resolvePackageDir Whether to resolve the relative path to an absolute
#' path via \code{\link{system.file}} when the \code{package} attribute is
#' present in a dependency object.
#' @return dependencies A list of \code{\link{htmlDependency}} objects with
#' redundancies removed.
#'
#' @export
resolveDependencies <- function(dependencies, resolvePackageDir = TRUE) {
# Remove nulls
deps <- dependencies[!sapply(dependencies, is.null)]
# Get names and numeric versions in vector/list form
depnames <- sapply(deps, `[[`, "name")
depvers <- numeric_version(sapply(deps, `[[`, "version"))
# Get latest version of each dependency. `unique` uses the first occurrence of
# each dependency name, which is important for inter-dependent libraries.
return(lapply(unique(depnames), function(depname) {
# Sort by depname equality, then by version. Since na.last=NA, all elements
# whose names do not match will not be included in the sorted vector.
sorted <- order(ifelse(depnames == depname, TRUE, NA), depvers,
na.last = NA, decreasing = TRUE)
# The first element in the list is the one with the largest version.
dep <- deps[[sorted[[1]]]]
if (resolvePackageDir && !is.null(dep$package)) {
dir <- dep$src$file
if (!is.null(dir)) dep$src$file <- system.file(dir, package = dep$package)
dep$package <- NULL
}
dep
}))
}
# Remove `remove` from `dependencies` if the name matches.
# dependencies is a named list of dependencies.
# remove is a named list of dependencies that take priority.
# If warnOnConflict, then warn when a dependency is being removed because of an
# older version already being loaded.
#' Subtract dependencies
#'
#' Remove a set of dependencies from another list of dependencies. The set of
#' dependencies to remove can be expressed as either a character vector or a
#' list; if the latter, a warning can be emitted if the version of the
#' dependency being removed is later than the version of the dependency object
#' that is causing the removal.
#'
#' @param dependencies A list of \code{\link{htmlDependency}} objects from which
#' dependencies should be removed.
#' @param remove A list of \code{\link{htmlDependency}} objects indicating which
#' dependencies should be removed, or a character vector indicating dependency
#' names.
#' @param warnOnConflict If \code{TRUE}, a warning is emitted for each
#' dependency that is removed if the corresponding dependency in \code{remove}
#' has a lower version number. Has no effect if \code{remove} is provided as a
#' character vector.
#'
#' @return A list of \code{\link{htmlDependency}} objects that don't intersect
#' with \code{remove}.
#'
#' @export
subtractDependencies <- function(dependencies, remove, warnOnConflict = TRUE) {
depnames <- sapply(dependencies, `[[`, "name")
rmnames <- if (is.character(remove))
remove
else
sapply(remove, `[[`, "name")
matches <- depnames %in% rmnames
if (warnOnConflict && !is.character(remove)) {
for (loser in dependencies[matches]) {
winner <- remove[[head(rmnames == loser$name, 1)]]
if (compareVersion(loser$version, winner$version) > 0) {
warning(sprintf(paste("The dependency %s %s conflicts with",
"version %s"), loser$name, loser$version, winner$version
))
}
}
}
# Return only deps that weren't in remove
return(dependencies[!matches])
}
# Given a vector or list, drop all the NULL items in it
dropNulls <- function(x) {
x[!vapply(x, is.null, FUN.VALUE=logical(1))]
}
nullOrEmpty <- function(x) {
length(x) == 0
}
# Given a vector or list, drop all the NULL or length-0 items in it
dropNullsOrEmpty <- function(x) {
x[!vapply(x, nullOrEmpty, FUN.VALUE=logical(1))]
}
isTag <- function(x) {
inherits(x, "shiny.tag")
}
#' @rdname print.html
#' @export
print.shiny.tag <- function(x, browse = is.browsable(x), ...) {
if (browse)
html_print(x)
else
print(HTML(as.character(x)), ...)
invisible(x)
}
# indent can be numeric to indicate an initial indent level,
# or FALSE to suppress
#' @export
format.shiny.tag <- function(x, ..., singletons = character(0), indent = 0) {
as.character(renderTags(x, singletons = singletons, indent = indent)$html)
}
#' @export
as.character.shiny.tag <- function(x, ...) {
as.character(renderTags(x)$html)
}
#' @export
as.character.html <- function(x, ...) {
as.vector(enc2utf8(x))
}
#' @export
print.shiny.tag.list <- print.shiny.tag
#' @export
format.shiny.tag.list <- format.shiny.tag
#' @export
as.character.shiny.tag.list <- as.character.shiny.tag
#' Print method for HTML/tags
#'
#' S3 method for printing HTML that prints markup or renders HTML in a web
#' browser.
#'
#' @param x The value to print.
#' @param browse If \code{TRUE}, the HTML will be rendered and displayed in a
#' browser (or possibly another HTML viewer supplied by the environment via
#' the \code{viewer} option). If \code{FALSE} then the HTML object's markup
#' will be rendered at the console.
#' @param ... Additional arguments passed to print.
#'
#' @export
print.html <- function(x, ..., browse = is.browsable(x)) {
if (browse)
html_print(HTML(x))
else
cat(x, "\n", sep = "")
invisible(x)
}
#' @export
format.html <- function(x, ...) {
as.character(x)
}
normalizeText <- function(text) {
if (!is.null(attr(text, "html", TRUE)))
text
else
htmlEscape(text, attribute=FALSE)
}
#' @name tag
#' @rdname tag
#' @export
tagList <- function(...) {
lst <- list(...)
class(lst) <- c("shiny.tag.list", "list")
return(lst)
}
#' @rdname tag
#' @export
tagAppendAttributes <- function(tag, ...) {
tag$attribs <- c(tag$attribs, list(...))
tag
}
#' @param attr The name of an attribute.
#' @rdname tag
#' @export
tagHasAttribute <- function(tag, attr) {
result <- attr %in% names(tag$attribs)
result
}
#' @rdname tag
#' @export
tagGetAttribute <- function(tag, attr) {
# Find out which positions in the attributes list correspond to the given attr
attribs <- tag$attribs
attrIdx <- which(attr == names(attribs))
if (length(attrIdx) == 0) {
return (NULL)
}
# Convert all attribs to chars explicitly; prevents us from messing up factors
result <- lapply(attribs[attrIdx], as.character)
# Separate multiple attributes with the same name
result <- paste(result, collapse = " ")
result
}
#' @rdname tag
#' @export
tagAppendChild <- function(tag, child) {
tag$children[[length(tag$children)+1]] <- child
tag
}
#' @rdname tag
#' @export
tagAppendChildren <- function(tag, ..., list = NULL) {
tag$children <- c(tag$children, c(list(...), list))
tag
}
#' @rdname tag
#' @export
tagSetChildren <- function(tag, ..., list = NULL) {
tag$children <- c(list(...), list)
tag
}
#' HTML Tag Object
#'
#' \code{tag()} creates an HTML tag definition. Note that all of the valid HTML5
#' tags are already defined in the \code{\link{tags}} environment so these
#' functions should only be used to generate additional tags.
#' \code{tagAppendChild()} and \code{tagList()} are for supporting package
#' authors who wish to create their own sets of tags; see the contents of
#' bootstrap.R for examples.
#' @param _tag_name HTML tag name
#' @param varArgs List of attributes and children of the element. Named list
#' items become attributes, and unnamed list items become children. Valid
#' children are tags, single-character character vectors (which become text
#' nodes), and raw HTML (see \code{\link{HTML}}). You can also pass lists that
#' contain tags, text nodes, and HTML.
#' @param tag A tag to append child elements to.
#' @param child A child element to append to a parent tag.
#' @param ... Unnamed items that comprise this list of tags.
#' @param list An optional list of elements. Can be used with or instead of the
#' \code{...} items.
#' @return An HTML tag object that can be rendered as HTML using
#' \code{\link{as.character}()}.
#' @export
#' @examples
#' tagList(tags$h1("Title"),
#' tags$h2("Header text"),
#' tags$p("Text here"))
#'
#' # Can also convert a regular list to a tagList (internal data structure isn't
#' # exactly the same, but when rendered to HTML, the output is the same).
#' x <- list(tags$h1("Title"),
#' tags$h2("Header text"),
#' tags$p("Text here"))
#' tagList(x)
tag <- function(`_tag_name`, varArgs) {
# Get arg names; if not a named list, use vector of empty strings
varArgsNames <- names(varArgs)
if (is.null(varArgsNames))
varArgsNames <- character(length=length(varArgs))
# Named arguments become attribs, dropping NULL and length-0 values
named_idx <- nzchar(varArgsNames)
attribs <- dropNullsOrEmpty(varArgs[named_idx])
# Unnamed arguments are flattened and added as children.
# Use unname() to remove the names attribute from the list, which would
# consist of empty strings anyway.
children <- unname(varArgs[!named_idx])
# Return tag data structure
structure(
list(name = `_tag_name`,
attribs = attribs,
children = children),
class = "shiny.tag"
)
}
isTagList <- function(x) {
is.list(x) && (inherits(x, "shiny.tag.list") || identical(class(x), "list"))
}
tagWrite <- function(tag, textWriter, indent=0, eol = "\n") {
if (length(tag) == 0)
return (NULL)
# optionally process a list of tags
if (!isTag(tag) && isTagList(tag)) {
tag <- dropNullsOrEmpty(flattenTags(tag))
lapply(tag, tagWrite, textWriter, indent)
return (NULL)
}
nextIndent <- if (is.numeric(indent)) indent + 1 else indent
indent <- if (is.numeric(indent)) indent else 0
# compute indent text
indentText <- paste(rep(" ", indent*2), collapse="")
# Check if it's just text (may either be plain-text or HTML)
if (is.character(tag)) {
textWriter(indentText)
textWriter(normalizeText(tag))
textWriter(eol)
return (NULL)
}
# write tag name
textWriter(paste8(indentText, "<", tag$name, sep=""))
# Convert all attribs to chars explicitly; prevents us from messing up factors
attribs <- lapply(tag$attribs, as.character)
# concatenate attributes
# split() is very slow, so avoid it if possible
if (anyDuplicated(names(attribs)))
attribs <- lapply(split(attribs, names(attribs)), paste, collapse = " ")
# write attributes
for (attrib in names(attribs)) {
attribValue <- attribs[[attrib]]
if (!is.na(attribValue)) {
if (is.logical(attribValue))
attribValue <- tolower(attribValue)
text <- htmlEscape(attribValue, attribute=TRUE)
textWriter(paste8(" ", attrib,"=\"", text, "\"", sep=""))
}
else {
textWriter(paste8(" ", attrib, sep=""))
}
}
# write any children
children <- dropNullsOrEmpty(flattenTags(tag$children))
if (length(children) > 0) {
textWriter(">")
# special case for a single child text node (skip newlines and indentation)
if ((length(children) == 1) && is.character(children[[1]]) ) {
textWriter(paste8(normalizeText(children[[1]]), "", tag$name, ">", eol,
sep=""))
}
else {
textWriter("\n")
for (child in children)
tagWrite(child, textWriter, nextIndent)
textWriter(paste8(indentText, "", tag$name, ">", eol, sep=""))
}
}
else {
# only self-close void elements
# (see: http://dev.w3.org/html5/spec/single-page.html#void-elements)
if (tag$name %in% c("area", "base", "br", "col", "command", "embed", "hr",
"img", "input", "keygen", "link", "meta", "param",
"source", "track", "wbr")) {
textWriter(paste8("/>", eol, sep=""))
}
else {
textWriter(paste8(">", tag$name, ">", eol, sep=""))
}
}
}
#' Render tags into HTML
#'
#' Renders tags (and objects that can be converted into tags using
#' \code{\link{as.tags}}) into HTML. (Generally intended to be called from web
#' framework libraries, not directly by most users--see
#' \code{\link{print.html}(browse=TRUE)} for higher level rendering.)
#'
#' @param x Tag object(s) to render
#' @param singletons A list of \link{singleton} signatures to consider already
#' rendered; any matching singletons will be dropped instead of rendered.
#' (This is useful (only?) for incremental rendering.)
#' @param indent Initial indent level, or \code{FALSE} if no indentation should
#' be used.
#'
#' @return \code{renderTags} returns a list with the following variables:
#' \describe{
#' \item{\code{head}}{An \code{\link{HTML}} string that should be included in
#' \code{}.
#' }
#' \item{\code{singletons}}{Character vector of singleton signatures that are
#' known after rendering.
#' }
#' \item{\code{dependencies}}{A list of \link[=resolveDependencies]{resolved}
#' \code{\link{htmlDependency}} objects.
#' }
#' \item{\code{html}}{An \code{\link{HTML}} string that represents the main
#' HTML that was rendered.
#' }
#' }
#'
#' @export
renderTags <- function(x, singletons = character(0), indent = 0) {
x <- tagify(x)
# Do singleton and head processing before rendering
singletonInfo <- takeSingletons(x, singletons)
headInfo <- takeHeads(singletonInfo$ui)
deps <- resolveDependencies(findDependencies(singletonInfo$ui, tagify = FALSE))
headIndent <- if (is.numeric(indent)) indent + 1 else indent
headHtml <- doRenderTags(headInfo$head, indent = headIndent)
bodyHtml <- doRenderTags(headInfo$ui, indent = indent)
return(list(head = headHtml,
singletons = singletonInfo$singletons,
dependencies = deps,
html = bodyHtml))
}
#' @details \code{doRenderTags} is intended for very low-level use; it ignores
#' singleton, head, and dependency handling, and simply renders the given tag
#' objects as HTML.
#' @return \code{doRenderTags} returns a simple \code{\link{HTML}} string.
#' @rdname renderTags
#' @export
doRenderTags <- function(x, indent = 0) {
# The text that is written to this connWriter will be converted to
# UTF-8 using enc2utf8. The rendered output will always be UTF-8
# encoded.
#
# We use a file() here instead of textConnection() or paste/c to
# avoid the overhead of copying, which is huge for moderately
# large numbers of calls to connWriter(). Generally when you want
# to incrementally build up a long string out of immutable ones,
# you want to use a mutable/growable string buffer of some kind;
# since R doesn't have something like that (that I know of),
# file() is the next best thing.
conn <- file(open="w+b", encoding = "UTF-8")
# Track how many bytes we write, so we can read in the right amount
# later with readChar.
bytes <- 0
connWriter <- function(text) {
raw <- charToRaw(enc2utf8(text))
bytes <<- bytes + length(raw)
# This is actually writing UTF-8 bytes, not chars
writeBin(raw, conn)
}
htmlResult <- tryCatch(
{
tagWrite(x, connWriter, indent)
flush(conn)
# Strip off trailing \n (which is always there) but make sure not to
# specify a negative number of chars.
bytes <- max(bytes - 1, 0)
readChar(conn, bytes, useBytes = TRUE)
},
finally = close(conn)
)
Encoding(htmlResult) <- "UTF-8"
return(HTML(htmlResult))
}
# Walk a tree of tag objects, rewriting objects according to func.
# preorder=TRUE means preorder tree traversal, that is, an object
# should be rewritten before its children.
rewriteTags <- function(ui, func, preorder) {
if (preorder)
ui <- func(ui)
if (isTag(ui)) {
ui$children[] <- lapply(ui$children, rewriteTags, func, preorder)
} else if (isTagList(ui)) {
ui[] <- lapply(ui, rewriteTags, func, preorder)
}
if (!preorder)
ui <- func(ui)
return(ui)
}
#' Singleton manipulation functions
#'
#' Functions for manipulating \code{\link{singleton}} objects in tag
#' hierarchies. Intended for framework authors.
#'
#' @rdname singleton_tools
#' @name singleton_tools
NULL
#' @param ui Tag object or lists of tag objects. See \link{builder} topic.
#' @return \code{surroundSingletons} preprocesses a tag object by changing any
#' singleton X into X'
#' where sig is the sha1 of X, and X' is X minus the singleton attribute.
#' @rdname singleton_tools
#' @export
surroundSingletons <- local({
# In the case of nested singletons, outer singletons are processed
# before inner singletons (otherwise the processing of inner
# singletons would cause the sha1 of the outer singletons to be
# different).
surroundSingleton <- function(uiObj) {
if (is.singleton(uiObj)) {
sig <- digest(uiObj, "sha1")
uiObj <- singleton(uiObj, FALSE)
return(tagList(
HTML(sprintf("", sig)),
uiObj,
HTML(sprintf("", sig))
))
} else {
uiObj
}
}
function(ui) {
rewriteTags(ui, surroundSingleton, TRUE)
}
})
#' @param singletons Character vector of singleton signatures that have already
#' been encountered (i.e. returned from previous calls to
#' \code{takeSingletons}).
#' @param desingleton Logical value indicating whether singletons that are
#' encountered should have the singleton attribute removed.
#' @return \code{takeSingletons} returns a list with the elements \code{ui} (the
#' processed tag objects with any duplicate singleton objects removed) and
#' \code{singletons} (the list of known singleton signatures).
#' @rdname singleton_tools
#' @export
takeSingletons <- function(ui, singletons=character(0), desingleton=TRUE) {
result <- rewriteTags(ui, function(uiObj) {
if (is.singleton(uiObj)) {
sig <- digest(uiObj, "sha1")
if (sig %in% singletons)
return(NULL)
singletons <<- append(singletons, sig)
if (desingleton)
uiObj <- singleton(uiObj, FALSE)
return(uiObj)
} else {
return(uiObj)
}
}, TRUE)
return(list(ui=result, singletons=singletons))
}
# Given a tag object, extract out any children of tags$head
# and return them separate from the body.
takeHeads <- function(ui) {
headItems <- list()
result <- rewriteTags(ui, function(uiObj) {
if (isTag(uiObj) && tolower(uiObj$name) == "head") {
headItems <<- append(headItems, uiObj$children)
return(NULL)
}
return(uiObj)
}, FALSE)
return(list(ui=result, head=headItems))
}
#' Collect attached dependencies from HTML tag object
#'
#' Walks a hierarchy of tags looking for attached dependencies.
#'
#' @param tags A tag-like object to search for dependencies.
#' @param tagify Whether to tagify the input before searching for dependencies.
#'
#' @return A list of \code{\link{htmlDependency}} objects.
#'
#' @export
findDependencies <- function(tags, tagify = TRUE) {
if (isTRUE(tagify)) {
tags <- tagify(tags)
}
dep <- htmlDependencies(tags)
if (!is.null(dep) && inherits(dep, "html_dependency"))
dep <- list(dep)
children <- if (is.list(tags)) {
if (isTag(tags)) {
tags$children
} else {
tags
}
}
childDeps <- unlist(lapply(children, findDependencies, tagify = FALSE), recursive = FALSE)
c(childDeps, if (!is.null(dep)) dep)
}
#' HTML Builder Functions
#'
#' Simple functions for constructing HTML documents.
#'
#' The \code{tags} environment contains convenience functions for all valid
#' HTML5 tags. To generate tags that are not part of the HTML5 specification,
#' you can use the \code{\link{tag}()} function.
#'
#' Dedicated functions are available for the most common HTML tags that do not
#' conflict with common R functions.
#'
#' The result from these functions is a tag object, which can be converted using
#' \code{\link{as.character}()}.
#'
#' @name builder
#' @param ... Attributes and children of the element. Named arguments become
#' attributes, and positional arguments become children. Valid children are
#' tags, single-character character vectors (which become text nodes), raw
#' HTML (see \code{\link{HTML}}), and \code{html_dependency} objects. You can
#' also pass lists that contain tags, text nodes, or HTML.
#' @export tags
#' @examples
#' doc <- tags$html(
#' tags$head(
#' tags$title('My first page')
#' ),
#' tags$body(
#' h1('My first heading'),
#' p('My first paragraph, with some ',
#' strong('bold'),
#' ' text.'),
#' div(id='myDiv', class='simpleDiv',
#' 'Here is a div with some attributes.')
#' )
#' )
#' cat(as.character(doc))
NULL
#' @rdname builder
#' @format NULL
#' @docType NULL
#' @keywords NULL
tags <- list(
a = function(...) tag("a", list(...)),
abbr = function(...) tag("abbr", list(...)),
address = function(...) tag("address", list(...)),
area = function(...) tag("area", list(...)),
article = function(...) tag("article", list(...)),
aside = function(...) tag("aside", list(...)),
audio = function(...) tag("audio", list(...)),
b = function(...) tag("b", list(...)),
base = function(...) tag("base", list(...)),
bdi = function(...) tag("bdi", list(...)),
bdo = function(...) tag("bdo", list(...)),
blockquote = function(...) tag("blockquote", list(...)),
body = function(...) tag("body", list(...)),
br = function(...) tag("br", list(...)),
button = function(...) tag("button", list(...)),
canvas = function(...) tag("canvas", list(...)),
caption = function(...) tag("caption", list(...)),
cite = function(...) tag("cite", list(...)),
code = function(...) tag("code", list(...)),
col = function(...) tag("col", list(...)),
colgroup = function(...) tag("colgroup", list(...)),
command = function(...) tag("command", list(...)),
data = function(...) tag("data", list(...)),
datalist = function(...) tag("datalist", list(...)),
dd = function(...) tag("dd", list(...)),
del = function(...) tag("del", list(...)),
details = function(...) tag("details", list(...)),
dfn = function(...) tag("dfn", list(...)),
div = function(...) tag("div", list(...)),
dl = function(...) tag("dl", list(...)),
dt = function(...) tag("dt", list(...)),
em = function(...) tag("em", list(...)),
embed = function(...) tag("embed", list(...)),
eventsource = function(...) tag("eventsource", list(...)),
fieldset = function(...) tag("fieldset", list(...)),
figcaption = function(...) tag("figcaption", list(...)),
figure = function(...) tag("figure", list(...)),
footer = function(...) tag("footer", list(...)),
form = function(...) tag("form", list(...)),
h1 = function(...) tag("h1", list(...)),
h2 = function(...) tag("h2", list(...)),
h3 = function(...) tag("h3", list(...)),
h4 = function(...) tag("h4", list(...)),
h5 = function(...) tag("h5", list(...)),
h6 = function(...) tag("h6", list(...)),
head = function(...) tag("head", list(...)),
header = function(...) tag("header", list(...)),
hgroup = function(...) tag("hgroup", list(...)),
hr = function(...) tag("hr", list(...)),
html = function(...) tag("html", list(...)),
i = function(...) tag("i", list(...)),
iframe = function(...) tag("iframe", list(...)),
img = function(...) tag("img", list(...)),
input = function(...) tag("input", list(...)),
ins = function(...) tag("ins", list(...)),
kbd = function(...) tag("kbd", list(...)),
keygen = function(...) tag("keygen", list(...)),
label = function(...) tag("label", list(...)),
legend = function(...) tag("legend", list(...)),
li = function(...) tag("li", list(...)),
link = function(...) tag("link", list(...)),
mark = function(...) tag("mark", list(...)),
map = function(...) tag("map", list(...)),
menu = function(...) tag("menu", list(...)),
meta = function(...) tag("meta", list(...)),
meter = function(...) tag("meter", list(...)),
nav = function(...) tag("nav", list(...)),
noscript = function(...) tag("noscript", list(...)),
object = function(...) tag("object", list(...)),
ol = function(...) tag("ol", list(...)),
optgroup = function(...) tag("optgroup", list(...)),
option = function(...) tag("option", list(...)),
output = function(...) tag("output", list(...)),
p = function(...) tag("p", list(...)),
param = function(...) tag("param", list(...)),
pre = function(...) tag("pre", list(...)),
progress = function(...) tag("progress", list(...)),
q = function(...) tag("q", list(...)),
ruby = function(...) tag("ruby", list(...)),
rp = function(...) tag("rp", list(...)),
rt = function(...) tag("rt", list(...)),
s = function(...) tag("s", list(...)),
samp = function(...) tag("samp", list(...)),
script = function(...) tag("script", list(...)),
section = function(...) tag("section", list(...)),
select = function(...) tag("select", list(...)),
small = function(...) tag("small", list(...)),
source = function(...) tag("source", list(...)),
span = function(...) tag("span", list(...)),
strong = function(...) tag("strong", list(...)),
style = function(...) tag("style", list(...)),
sub = function(...) tag("sub", list(...)),
summary = function(...) tag("summary", list(...)),
sup = function(...) tag("sup", list(...)),
table = function(...) tag("table", list(...)),
tbody = function(...) tag("tbody", list(...)),
td = function(...) tag("td", list(...)),
textarea = function(...) tag("textarea", list(...)),
tfoot = function(...) tag("tfoot", list(...)),
th = function(...) tag("th", list(...)),
thead = function(...) tag("thead", list(...)),
time = function(...) tag("time", list(...)),
title = function(...) tag("title", list(...)),
tr = function(...) tag("tr", list(...)),
track = function(...) tag("track", list(...)),
u = function(...) tag("u", list(...)),
ul = function(...) tag("ul", list(...)),
var = function(...) tag("var", list(...)),
video = function(...) tag("video", list(...)),
wbr = function(...) tag("wbr", list(...))
)
#' Mark Characters as HTML
#'
#' Marks the given text as HTML, which means the \link{tag} functions will know
#' not to perform HTML escaping on it.
#'
#' @param text The text value to mark with HTML
#' @param ... Any additional values to be converted to character and
#' concatenated together
#' @return The same value, but marked as HTML.
#'
#' @examples
#' el <- div(HTML("I like turtles"))
#' cat(as.character(el))
#'
#' @export
HTML <- function(text, ...) {
htmlText <- c(text, as.character(list(...)))
htmlText <- paste8(htmlText, collapse=" ")
attr(htmlText, "html") <- TRUE
class(htmlText) <- c("html", "character")
htmlText
}
#' Evaluate an expression using \code{tags}
#'
#' This function makes it simpler to write HTML-generating code. Instead of
#' needing to specify \code{tags} each time a tag function is used, as in
#' \code{tags$div()} and \code{tags$p()}, code inside \code{withTags} is
#' evaluated with \code{tags} searched first, so you can simply use
#' \code{div()} and \code{p()}.
#'
#' If your code uses an object which happens to have the same name as an
#' HTML tag function, such as \code{source()} or \code{summary()}, it will call
#' the tag function. To call the intended (non-tags function), specify the
#' namespace, as in \code{base::source()} or \code{base::summary()}.
#'
#' @param code A set of tags.
#'
#' @examples
#' # Using tags$ each time
#' tags$div(class = "myclass",
#' tags$h3("header"),
#' tags$p("text")
#' )
#'
#' # Equivalent to above, but using withTags
#' withTags(
#' div(class = "myclass",
#' h3("header"),
#' p("text")
#' )
#' )
#'
#'
#' @export
withTags <- function(code) {
eval(substitute(code), envir = as.list(tags), enclos = parent.frame())
}
# Make sure any objects in the tree that can be converted to tags, have been
tagify <- function(x) {
rewriteTags(x, function(uiObj) {
if (isTag(uiObj) || isTagList(uiObj) || is.character(uiObj))
return(uiObj)
else
return(tagify(as.tags(uiObj)))
}, FALSE)
}
# Given a list of tags, lists, and other items, return a flat list, where the
# items from the inner, nested lists are pulled to the top level, recursively.
flattenTags <- function(x) {
if (isTag(x)) {
# For tags, wrap them into a list (which will be unwrapped by caller)
list(x)
} else if (isTagList(x)) {
if (length(x) == 0) {
# Empty lists are simply returned
x
} else {
# For items that are lists (but not tags), recurse
unlist(lapply(x, flattenTags), recursive = FALSE)
}
} else if (is.character(x)){
# This will preserve attributes if x is a character with attribute,
# like what HTML() produces
list(x)
} else {
# For other items, coerce to character and wrap them into a list (which
# will be unwrapped by caller). Note that this will strip attributes.
flattenTags(as.tags(x))
}
}
#' Convert a value to tags
#'
#' An S3 method for converting arbitrary values to a value that can be used as
#' the child of a tag or \code{tagList}. The default implementation simply calls
#' \code{\link[base]{as.character}}.
#'
#' @param x Object to be converted.
#' @param ... Any additional parameters.
#'
#' @export
as.tags <- function(x, ...) {
UseMethod("as.tags")
}
#' @export
as.tags.default <- function(x, ...) {
if (is.list(x) && !isTagList(x))
unclass(x)
else
tagList(as.character(x))
}
#' @export
as.tags.html <- function(x, ...) {
x
}
#' @export
as.tags.shiny.tag <- function(x, ...) {
x
}
#' @export
as.tags.shiny.tag.list <- function(x, ...) {
x
}
#' @export
as.tags.character <- function(x, ...) {
# For printing as.tags("") directly at console, without dropping any
# attached dependencies
tagList(x)
}
#' @export
as.tags.html_dependency <- function(x, ...) {
attachDependencies(tagList(), x)
}
#' Preserve HTML regions
#'
#' Use "magic" HTML comments to protect regions of HTML from being modified by
#' text processing tools.
#'
#' Text processing tools like markdown and pandoc are designed to turn
#' human-friendly markup into common output formats like HTML. This works well
#' for most prose, but components that generate their own HTML may break if
#' their markup is interpreted as the input language. The \code{htmlPreserve}
#' function is used to mark regions of an input document as containing pure HTML
#' that must not be modified. This is achieved by substituting each such region
#' with a benign but unique string before processing, and undoing those
#' substitutions after processing.
#'
#' @param x A character vector of HTML to be preserved.
#'
#' @return \code{htmlPreserve} returns a single-element character vector with
#' "magic" HTML comments surrounding the original text (unless the original
#' text was empty, in which case an empty string is returned).
#'
#' @examples
#' # htmlPreserve will prevent ""
#' # from getting an tag inserted in the middle
#' markup <- paste(sep = "\n",
#' "This is *emphasized* text in markdown.",
#' htmlPreserve(""),
#' "Here is some more *emphasized text*."
#' )
#' extracted <- extractPreserveChunks(markup)
#' markup <- extracted$value
#' # Just think of this next line as Markdown processing
#' output <- gsub("\\*(.*?)\\*", "\\1", markup)
#' output <- restorePreserveChunks(output, extracted$chunks)
#' output
#'
#' @export
htmlPreserve <- function(x) {
x <- paste(x, collapse = "\r\n")
if (nzchar(x))
sprintf("%s", x)
else
x
}
# Temporarily set x in env to value, evaluate expr, and
# then restore x to its original state
withTemporary <- function(env, x, value, expr, unset = FALSE) {
if (exists(x, envir = env, inherits = FALSE)) {
oldValue <- get(x, envir = env, inherits = FALSE)
on.exit(
assign(x, oldValue, envir = env, inherits = FALSE),
add = TRUE)
} else {
on.exit(
rm(list = x, envir = env, inherits = FALSE),
add = TRUE
)
}
if (!missing(value) && !isTRUE(unset))
assign(x, value, envir = env, inherits = FALSE)
else {
if (exists(x, envir = env, inherits = FALSE))
rm(list = x, envir = env, inherits = FALSE)
}
force(expr)
}
# Evaluate an expression using Shiny's own private stream of
# randomness (not affected by set.seed).
withPrivateSeed <- local({
ownSeed <- NULL
function(expr) {
withTemporary(.GlobalEnv, ".Random.seed",
ownSeed, unset=is.null(ownSeed), {
tryCatch({
expr
}, finally = {ownSeed <<- .Random.seed})
}
)
}
})
# extract_preserve_chunks looks for regions in strval marked by
# ... and replaces each such region
# with a long unique ID. The return value is a list with $value as the string
# with the regions replaced, and $chunks as a named character vector where the
# names are the IDs and the values are the regions that were extracted.
#
# Nested regions are handled appropriately; the outermost region is what's used
# and any inner regions simply have their boundaries removed before the values
# are stashed in $chunks.
#' @return \code{extractPreserveChunks} returns a list with two named elements:
#' \code{value} is the string with the regions replaced, and \code{chunks} is
#' a named character vector where the names are the IDs and the values are the
#' regions that were extracted.
#' @rdname htmlPreserve
#' @export
extractPreserveChunks <- function(strval) {
# Literal start/end marker text. Case sensitive.
startmarker <- ""
endmarker <- ""
# Start and end marker length MUST be different, it's how we tell them apart
startmarker_len <- nchar(startmarker)
endmarker_len <- nchar(endmarker)
# Pattern must match both start and end markers
pattern <- ""
# It simplifies string handling greatly to collapse multiple char elements
if (length(strval) != 1)
strval <- paste(strval, collapse = "\n")
# matches contains the index of all the start and end markers
matches <- gregexpr(pattern, strval)[[1]]
lengths <- attr(matches, "match.length", TRUE)
# No markers? Just return.
if (matches[[1]] == -1)
return(list(value = strval, chunks = character(0)))
# If TRUE, it's a start; if FALSE, it's an end
boundary_type <- lengths == startmarker_len
# Positive number means we're inside a region, zero means we just exited to
# the top-level, negative number means error (an end without matching start).
# For example:
# boundary_type - TRUE TRUE FALSE FALSE TRUE FALSE
# preserve_level - 1 2 1 0 1 0
preserve_level <- cumsum(ifelse(boundary_type, 1, -1))
# Sanity check.
if (any(preserve_level < 0) || tail(preserve_level, 1) != 0) {
stop("Invalid nesting of html_preserve directives")
}
# Identify all the top-level boundary markers. We want to find all of the
# elements of preserve_level whose value is 0 and preceding value is 1, or
# whose value is 1 and preceding value is 0. Since we know that preserve_level
# values can only go up or down by 1, we can simply shift preserve_level by
# one element and add it to preserve_level; in the result, any value of 1 is a
# match.
is_top_level <- 1 == (preserve_level + c(0, preserve_level[-length(preserve_level)]))
preserved <- character(0)
top_level_matches <- matches[is_top_level]
# Iterate backwards so string mutation doesn't screw up positions for future
# iterations
for (i in seq.int(length(top_level_matches) - 1, 1, by = -2)) {
start_outer <- top_level_matches[[i]]
start_inner <- start_outer + startmarker_len
end_inner <- top_level_matches[[i+1]]
end_outer <- end_inner + endmarker_len
id <- withPrivateSeed(
paste("preserve", paste(
format(as.hexmode(sample(256, 8, replace = TRUE)-1), width=2),
collapse = ""),
sep = "")
)
preserved[id] <- gsub(pattern, "", substr(strval, start_inner, end_inner-1))
strval <- paste(
substr(strval, 1, start_outer - 1),
id,
substr(strval, end_outer, nchar(strval)),
sep="")
substr(strval, start_outer, end_outer-1) <- id
}
list(value = strval, chunks = preserved)
}
#' @param strval Input string from which to extract/restore chunks.
#' @param chunks The \code{chunks} element of the return value of
#' \code{extractPreserveChunks}.
#' @return \code{restorePreserveChunks} returns a character vector with the
#' chunk IDs replaced with their original values.
#' @rdname htmlPreserve
#' @export
restorePreserveChunks <- function(strval, chunks) {
strval <- enc2utf8(strval)
chunks <- enc2utf8(chunks)
for (id in names(chunks))
strval <- gsub(id, chunks[[id]], strval, fixed = TRUE, useBytes = TRUE)
Encoding(strval) <- 'UTF-8'
strval
}
#' Knitr S3 methods
#'
#' These S3 methods are necessary to allow HTML tags to print themselves in
#' knitr/rmarkdown documents.
#'
#' @name knitr_methods
#' @param x Object to knit_print
#' @param ... Additional knit_print arguments
NULL
#' @rdname knitr_methods
#' @export
knit_print.shiny.tag <- function(x, ...) {
x <- tagify(x)
output <- surroundSingletons(x)
deps <- resolveDependencies(findDependencies(x, tagify = FALSE), resolvePackageDir = FALSE)
content <- takeHeads(output)
head_content <- doRenderTags(tagList(content$head))
meta <- if (length(head_content) > 1 || head_content != "") {
list(structure(head_content, class = "shiny_head"))
}
meta <- c(meta, deps)
knitr::asis_output(
htmlPreserve(format(content$ui, indent=FALSE)),
meta = meta)
}
#' @rdname knitr_methods
#' @export
knit_print.html <- function(x, ...) {
deps <- resolveDependencies(findDependencies(x, tagify = FALSE))
knitr::asis_output(htmlPreserve(as.character(x)),
meta = if (length(deps)) list(deps))
}
#' @rdname knitr_methods
#' @export
knit_print.shiny.tag.list <- knit_print.shiny.tag
#' @rdname builder
#' @export
p <- function(...) tags$p(...)
#' @rdname builder
#' @export
h1 <- function(...) tags$h1(...)
#' @rdname builder
#' @export
h2 <- function(...) tags$h2(...)
#' @rdname builder
#' @export
h3 <- function(...) tags$h3(...)
#' @rdname builder
#' @export
h4 <- function(...) tags$h4(...)
#' @rdname builder
#' @export
h5 <- function(...) tags$h5(...)
#' @rdname builder
#' @export
h6 <- function(...) tags$h6(...)
#' @rdname builder
#' @export
a <- function(...) tags$a(...)
#' @rdname builder
#' @export
br <- function(...) tags$br(...)
#' @rdname builder
#' @export
div <- function(...) tags$div(...)
#' @rdname builder
#' @export
span <- function(...) tags$span(...)
#' @rdname builder
#' @export
pre <- function(...) tags$pre(...)
#' @rdname builder
#' @export
code <- function(...) tags$code(...)
#' @rdname builder
#' @export
img <- function(...) tags$img(...)
#' @rdname builder
#' @export
strong <- function(...) tags$strong(...)
#' @rdname builder
#' @export
em <- function(...) tags$em(...)
#' @rdname builder
#' @export
hr <- function(...) tags$hr(...)
#' Include Content From a File
#'
#' Load HTML, text, or rendered Markdown from a file and turn into HTML.
#'
#' These functions provide a convenient way to include an extensive amount of
#' HTML, textual, Markdown, CSS, or JavaScript content, rather than using a
#' large literal R string.
#'
#' @param path The path of the file to be included. It is highly recommended to
#' use a relative path (the base path being the Shiny application directory),
#' not an absolute path.
#'
#' @rdname include
#' @name include
#' @aliases includeHTML
#' @export
includeHTML <- function(path) {
lines <- readLines(path, warn=FALSE, encoding='UTF-8')
return(HTML(paste8(lines, collapse='\r\n')))
}
#' @note \code{includeText} escapes its contents, but does no other processing.
#' This means that hard breaks and multiple spaces will be rendered as they
#' usually are in HTML: as a single space character. If you are looking for
#' preformatted text, wrap the call with \code{\link{pre}}, or consider using
#' \code{includeMarkdown} instead.
#'
#' @rdname include
#' @export
includeText <- function(path) {
lines <- readLines(path, warn=FALSE, encoding='UTF-8')
return(paste8(lines, collapse='\r\n'))
}
#' @note The \code{includeMarkdown} function requires the \code{markdown}
#' package.
#' @rdname include
#' @export
includeMarkdown <- function(path) {
html <- markdown::markdownToHTML(path, fragment.only=TRUE)
Encoding(html) <- 'UTF-8'
return(HTML(html))
}
#' @param ... Any additional attributes to be applied to the generated tag.
#' @rdname include
#' @export
includeCSS <- function(path, ...) {
lines <- readLines(path, warn=FALSE, encoding='UTF-8')
args <- list(...)
if (is.null(args$type))
args$type <- 'text/css'
return(do.call(tags$style,
c(list(HTML(paste8(lines, collapse='\r\n'))), args)))
}
#' @rdname include
#' @export
includeScript <- function(path, ...) {
lines <- readLines(path, warn=FALSE, encoding='UTF-8')
return(tags$script(HTML(paste8(lines, collapse='\r\n')), ...))
}
#' Include content only once
#'
#' Use \code{singleton} to wrap contents (tag, text, HTML, or lists) that should
#' be included in the generated document only once, yet may appear in the
#' document-generating code more than once. Only the first appearance of the
#' content (in document order) will be used.
#'
#' @param x A \code{\link{tag}}, text, \code{\link{HTML}}, or list.
#' @param value Whether the object should be a singleton.
#'
#' @export
singleton <- function(x, value = TRUE) {
attr(x, "htmltools.singleton") <- if (isTRUE(value)) TRUE else NULL
return(x)
}
#' @rdname singleton
#' @export
is.singleton <- function(x) {
isTRUE(attr(x, "htmltools.singleton"))
}
#' Validate proper CSS formatting of a unit
#'
#' Checks that the argument is valid for use as a CSS unit of length.
#'
#' \code{NULL} and \code{NA} are returned unchanged.
#'
#' Single element numeric vectors are returned as a character vector with the
#' number plus a suffix of \code{"px"}.
#'
#' Single element character vectors must be \code{"auto"} or \code{"inherit"},
#' or a number. If the number has a suffix, it must be valid: \code{px},
#' \code{\%}, \code{em}, \code{pt}, \code{in}, \code{cm}, \code{mm}, \code{ex},
#' \code{pc}, \code{vh}, \code{vw}, \code{vmin}, or \code{vmax}.
#' If the number has no suffix, the suffix \code{"px"} is appended.
#'
#'
#' Any other value will cause an error to be thrown.
#'
#' @param x The unit to validate. Will be treated as a number of pixels if a
#' unit is not specified.
#' @return A properly formatted CSS unit of length, if possible. Otherwise, will
#' throw an error.
#' @examples
#' validateCssUnit("10%")
#' validateCssUnit(400) #treated as '400px'
#' @export
validateCssUnit <- function(x) {
if (is.null(x) || is.na(x))
return(x)
if (length(x) > 1 || (!is.character(x) && !is.numeric(x)))
stop('CSS units must be a single-element numeric or character vector')
# if the input is a character vector consisting only of digits (e.g. "960"),
# coerce it to a numeric value
if (is.character(x) && nchar(x) > 0 && gsub("\\d*", "", x) == "")
x <- as.numeric(x)
pattern <-
"^(auto|inherit|((\\.\\d+)|(\\d+(\\.\\d+)?))(%|in|cm|mm|em|ex|pt|pc|px|vh|vw|vmin|vmax))$"
if (is.character(x) &&
!grepl(pattern, x)) {
stop('"', x, '" is not a valid CSS unit (e.g., "100%", "400px", "auto")')
} else if (is.numeric(x)) {
x <- paste(x, "px", sep = "")
}
x
}
#' CSS string helper
#'
#' Convenience function for building CSS style declarations (i.e. the string
#' that goes into a style attribute, or the parts that go inside curly braces in
#' a full stylesheet).
#'
#' CSS uses \code{'-'} (minus) as a separator character in property names, but
#' this is an inconvenient character to use in an R function argument name.
#' Instead, you can use \code{'.'} (period) and/or \code{'_'} (underscore) as
#' separator characters. For example, \code{css(font.size = "12px")} yields
#' \code{"font-size:12px;"}.
#'
#' To mark a property as \code{!important}, add a \code{'!'} character to the end
#' of the property name. (Since \code{'!'} is not normally a character that can be
#' used in an identifier in R, you'll need to put the name in double quotes or
#' backticks.)
#'
#' Argument values will be converted to strings using
#' \code{paste(collapse = " ")}. Any property with a value of \code{NULL} or
#' \code{""} (after paste) will be dropped.
#'
#' @param ... Named style properties, where the name is the property name and
#' the argument is the property value. See Details for conversion rules.
#' @param collapse_ (Note that the parameter name has a trailing underscore
#' character.) Character to use to collapse properties into a single string;
#' likely \code{""} (the default) for style attributes, and either \code{"\n"}
#' or \code{NULL} for style blocks.
#'
#' @examples
#' padding <- 6
#' css(
#' font.family = "Helvetica, sans-serif",
#' margin = paste0(c(10, 20, 10, 20), "px"),
#' "padding!" = if (!is.null(padding)) padding
#' )
#'
#' @export
css <- function(..., collapse_ = "") {
props <- list(...)
if (length(props) == 0) {
return("")
}
if (is.null(names(props)) || any(names(props) == "")) {
stop("cssList expects all arguments to be named")
}
# Necessary to make factors show up as level names, not numbers
props[] <- lapply(props, paste, collapse = " ")
# Drop null args
props <- props[!sapply(props, empty)]
if (length(props) == 0) {
return("")
}
# Replace all '.' and '_' in property names to '-'
names(props) <- gsub("[._]", "-", tolower(gsub("([A-Z])", "-\\1", names(props))))
# Create "!important" suffix for each property whose name ends with !, then
# remove the ! from the property name
important <- ifelse(grepl("!$", names(props), perl = TRUE), " !important", "")
names(props) <- sub("!$", "", names(props), perl = TRUE)
paste0(names(props), ":", props, important, ";", collapse = collapse_)
}
empty <- function(x) {
length(x) == 0 || (is.character(x) && !any(nzchar(x)))
}
htmltools/R/template.R 0000644 0001751 0000144 00000012353 13100232533 014450 0 ustar hornik users #' Process an HTML template
#'
#' Process an HTML template and return a tagList object. If the template is a
#' complete HTML document, then the returned object will also have class
#' \code{html_document}, and can be passed to the function
#' \code{\link{renderDocument}} to get the final HTML text.
#'
#' @param filename Path to an HTML template file. Incompatible with
#' \code{text_}.
#' @param ... Variable values to use when processing the template.
#' @param text_ A string to use as the template, instead of a file. Incompatible
#' with \code{filename}.
#' @param document_ Is this template a complete HTML document (\code{TRUE}), or
#' a fragment of HTML that is to be inserted into an HTML document
#' (\code{FALSE})? With \code{"auto"} (the default), auto-detect by searching
#' for the string \code{""} within the template.
#'
#' @seealso \code{\link{renderDocument}}
#' @export
#' @useDynLib htmltools, .registration = TRUE
#' @importFrom Rcpp sourceCpp
htmlTemplate <- function(filename = NULL, ..., text_ = NULL, document_ = "auto") {
if (!xor(is.null(filename), is.null(text_))) {
stop("htmlTemplate requires either `filename` or `text_`.")
}
if (!is.null(filename)) {
html <- readChar(filename, file.info(filename)$size, useBytes = TRUE)
Encoding(html) <- "UTF-8"
} else if(!is.null(text_)) {
text_ <- paste8(text_, collapse = "\n")
html <- enc2utf8(text_)
}
pieces <- template_dfa(html)
Encoding(pieces) <- "UTF-8"
# Create environment to evaluate code, as a child of the global env. This
# environment gets the ... arguments assigned as variables.
vars <- list(...)
if ("headContent" %in% names(vars)) {
stop("Can't use reserved argument name 'headContent'.")
}
vars$headContent <- function() HTML("")
env <- list2env(vars, parent = globalenv())
# All the odd-numbered pieces are HTML; all the even-numbered pieces are code
pieces <- mapply(
pieces,
rep_len(c(FALSE, TRUE), length.out = length(pieces)),
FUN = function(piece, isCode) {
if (isCode) {
eval(parse(text = piece), env)
} else if (piece == "") {
# Don't add leading/trailing '\n' if empty HTML string.
NULL
} else {
HTML(piece)
}
},
SIMPLIFY = FALSE
)
result <- tagList(pieces)
if (document_ == "auto") {
document_ = grepl("", html, ignore.case = TRUE)
}
if (document_) {
# The html.document class indicates that it's a complete document, and not
# just a set of tags.
class(result) <- c("html_document", class(result))
}
result
}
#' Render an html_document object
#'
#' This function renders \code{html_document} objects, and returns a string with
#' the final HTML content. It calls the \code{\link{renderTags}} function to
#' convert any shiny.tag objects to HTML. It also finds any any web dependencies
#' (created by \code{\link{htmlDependency}}) that are attached to the tags, and
#' inserts those. To do the insertion, this function finds the string
#' \code{""} in the document, and replaces it with the web
#' dependencies.
#'
#' @param x An object of class \code{html_document}, typically generated by the
#' \code{\link{htmlTemplate}} function.
#' @param deps Any extra web dependencies to add to the html document. This can
#' be an object created by \code{\link{htmlDependency}}, or a list of such
#' objects. These dependencies will be added first, before other dependencies.
#' @param processDep A function that takes a "raw" html_dependency object and
#' does further processing on it. For example, when \code{renderDocument} is
#' called from Shiny, the function \code{\link[shiny]{createWebDependency}} is
#' used; it modifies the href and tells Shiny to serve a particular path on
#' the filesystem.
#'
#' @export
renderDocument <- function(x, deps = NULL, processDep = identity) {
if (!inherits(x, "html_document")) {
stop("Object must be an object of class html_document")
}
if (inherits(deps, "html_dependency")) {
deps <- list(deps)
}
result <- renderTags(x)
# Figure out dependencies
deps <- c(deps, result$dependencies)
deps <- resolveDependencies(deps)
deps <- lapply(deps, processDep)
depStr <- paste(sapply(deps, function(dep) {
sprintf("%s[%s]", dep$name, dep$version)
}), collapse = ";")
depHtml <- renderDependencies(deps, "href")
# Put content in the section
head_content <- paste0(
' \n',
sprintf(' \n',
paste(result$singletons, collapse = ',')
),
sprintf(' \n',
depStr
),
depHtml,
c(result$head, recursive = TRUE)
)
# Need to mark result as UTF-8. If body is ASCII, it will be marked with
# encoding "unknown". If the head has UTF-8 characters and is marked as
# "UTF-8", the output string here will have the correct UTF-8 byte sequences,
# but will be marked as "unknown", which causes the wrong text to be
# displayed. See https://github.com/rstudio/shiny/issues/1395
res <- sub("", head_content, result$html, fixed = TRUE)
Encoding(res) <- "UTF-8"
res
}
htmltools/R/RcppExports.R 0000644 0001751 0000144 00000000336 13100231664 015130 0 ustar hornik users # Generated by using Rcpp::compileAttributes() -> do not edit by hand
# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
template_dfa <- function(x) {
.Call('htmltools_template_dfa', PACKAGE = 'htmltools', x)
}
htmltools/R/html_escape.R 0000644 0001751 0000144 00000002305 13100230764 015121 0 ustar hornik users
#' Escape HTML entities
#'
#' Escape HTML entities contained in a character vector so that it can be safely
#' included as text or an attribute value within an HTML document
#'
#' @param text Text to escape
#' @param attribute Escape for use as an attribute value
#'
#' @return Character vector with escaped text.
#'
#' @export
htmlEscape <- local({
.htmlSpecials <- list(
`&` = '&',
`<` = '<',
`>` = '>'
)
.htmlSpecialsPattern <- paste(names(.htmlSpecials), collapse='|')
.htmlSpecialsAttrib <- c(
.htmlSpecials,
`'` = ''',
`"` = '"',
`\r` = '
',
`\n` = '
'
)
.htmlSpecialsPatternAttrib <- paste(names(.htmlSpecialsAttrib), collapse='|')
function(text, attribute=FALSE) {
pattern <- if(attribute)
.htmlSpecialsPatternAttrib
else
.htmlSpecialsPattern
# Short circuit in the common case that there's nothing to escape
if (!any(grepl(pattern, text, useBytes = TRUE)))
return(text)
specials <- if(attribute)
.htmlSpecialsAttrib
else
.htmlSpecials
for (chr in names(specials)) {
text <- gsub(chr, specials[[chr]], text, fixed = TRUE, useBytes = TRUE)
}
return(text)
}
})
htmltools/R/html_print.R 0000644 0001751 0000144 00000006261 13100230764 015022 0 ustar hornik users #' Make an HTML object browsable
#'
#' By default, HTML objects display their HTML markup at the console when
#' printed. \code{browsable} can be used to make specific objects render as HTML
#' by default when printed at the console.
#'
#' You can override the default browsability of an HTML object by explicitly
#' passing \code{browse = TRUE} (or \code{FALSE}) to the \code{print} function.
#'
#' @param x The object to make browsable or not.
#' @param value Whether the object should be considered browsable.
#' @return \code{browsable} returns \code{x} with an extra attribute to indicate
#' that the value is browsable.
#' @export
browsable <- function(x, value = TRUE) {
attr(x, "browsable_html") <- if (isTRUE(value)) TRUE else NULL
return(x)
}
#' @return \code{is.browsable} returns \code{TRUE} if the value is browsable, or
#' \code{FALSE} if not.
#' @rdname browsable
#' @export
is.browsable <- function(x) {
return(isTRUE(attr(x, "browsable_html", exact=TRUE)))
}
#' Implementation of the print method for HTML
#'
#' Convenience method that provides an implementation of the
#' \code{\link[base:print]{print}} method for HTML content.
#'
#' @param html HTML content to print
#' @param background Background color for web page
#' @param viewer A function to be called with the URL or path to the generated
#' HTML page. Can be \code{NULL}, in which case no viewer will be invoked.
#'
#' @return Invisibly returns the URL or path of the generated HTML page.
#'
#' @export
html_print <- function(html, background = "white", viewer = getOption("viewer", utils::browseURL)) {
# define temporary directory for output
www_dir <- tempfile("viewhtml")
dir.create(www_dir)
# define output file
index_html <- file.path(www_dir, "index.html")
# save file
save_html(html, file = index_html, background = background, libdir = "lib")
# show it
if (!is.null(viewer))
viewer(index_html)
invisible(index_html)
}
#' Save an HTML object to a file
#'
#' Save the specified HTML object to a file, copying all of it's
#' dependencies to the directory specified via \code{libdir}.
#'
#' @param html HTML content to print
#' @param background Background color for web page
#' @param file File to write content to
#' @param libdir Directory to copy dependenies to
#'
#' @export
save_html <- function(html, file, background = "white", libdir = "lib") {
# ensure that the paths to dependencies are relative to the base
# directory where the webpage is being built.
dir <- dirname(file)
oldwd <- setwd(dir)
on.exit(setwd(oldwd), add = TRUE)
rendered <- renderTags(html)
deps <- lapply(rendered$dependencies, function(dep) {
dep <- copyDependencyToDir(dep, libdir, FALSE)
dep <- makeDependencyRelative(dep, dir, FALSE)
dep
})
# build the web-page
html <- c("",
"",
"",
"",
renderDependencies(deps, c("href", "file")),
rendered$head,
"",
sprintf("", htmlEscape(background)),
rendered$html,
"",
"")
# write it
writeLines(html, file, useBytes = TRUE)
}
htmltools/MD5 0000644 0001751 0000144 00000005017 13100571072 012624 0 ustar hornik users 630310adf5be92835b9544240f92376c *DESCRIPTION
41ac34eea891be5f999ed8b44f87e476 *NAMESPACE
738bee7e0dd52e6d69ccfe44c8dc0394 *NEWS
aa9302feb5eec2cedcb00f9d88e5af74 *R/RcppExports.R
411239656a10eb50c5d1d217b9b57ede *R/html_dependency.R
7bee8b23618adb2848412fedc7164709 *R/html_escape.R
b3e3d3353ebc757321b60abcad04397c *R/html_print.R
f02106c1cda38dbdd97d40370f99e4e1 *R/tags.R
31064a678bc8589cfd29497262ba2110 *R/template.R
ebcfaa458d3bdefadded43a4d64cfff9 *man/HTML.Rd
c00712c215b7bbb80a6287fee17f3c24 *man/as.tags.Rd
88494342535e91fa8972fd2fc3f1fde5 *man/browsable.Rd
6bfa2d7cdaca48f17caaa6b11902e28e *man/builder.Rd
bcfebb5f9577a5013fe33242fdec9645 *man/copyDependencyToDir.Rd
11bd91091ffdde442e05a6a26823a84d *man/css.Rd
83f5a6962792ba50b19b48dc1c65fd39 *man/findDependencies.Rd
b1b2d807ab611007bdf9b582b64e5f24 *man/htmlDependencies.Rd
9f7aaeaaa75598fbb0ab71e20359965d *man/htmlDependency.Rd
91c1824deb08f57376108765fd29dbaa *man/htmlEscape.Rd
475bf569370053b828bf69e4bb283825 *man/htmlPreserve.Rd
516afef01fac034a4e414e7515a7b71e *man/htmlTemplate.Rd
f0a6e81826dcaf3e212e70c63e67189e *man/html_print.Rd
4f34e99b07220d7a2fa41b9029a16862 *man/include.Rd
93bd5afcdac04bc4c5322122f0710e75 *man/knitr_methods.Rd
2b18a3612062f7783435b8dfd1e215f4 *man/makeDependencyRelative.Rd
16159aa45a251fb364e5fd1fd144d1d7 *man/print.html.Rd
504914f9f04e3a96f20d707b5acc341f *man/renderDependencies.Rd
dee26db7dd1d20fc2f13746ef9e9ae1d *man/renderDocument.Rd
5943238916b4b5866e49846183c95f98 *man/renderTags.Rd
3d7d639046044b164f7dabe61158c67d *man/resolveDependencies.Rd
3e8fac6287e21baa2e492fb2e581689b *man/save_html.Rd
72d8cd938a5a644116813539b07d0576 *man/singleton.Rd
0c319382fa19718f0d0da795c20501ce *man/singleton_tools.Rd
f0de725705e4f99a532bc4a9cc58664c *man/subtractDependencies.Rd
127fb8880888366a5c37c0b3b7eac069 *man/suppressDependencies.Rd
c36b122e98a5f4a6e89892f9cf8336ba *man/tag.Rd
cd3894dd85e4d84cc4ff5dc2a567fd4b *man/urlEncodePath.Rd
b107695e665e7daf7fb074bfd1ad4d94 *man/validateCssUnit.Rd
dec0c8e4a1f951e26daa06e9c07f986b *man/withTags.Rd
3305b464312f0fccbc917c491e79201d *src/RcppExports.cpp
a941e5cc1f933a4245b62b772a9263c5 *src/init.c
f7dbf02b3735f8a64fb1cc9264416713 *src/template.cpp
d5386f261693f9f4a5dda7b6fe0aa9f0 *tests/test-all.R
4de059d582d96a7c86907beb670b819d *tests/testthat/template-basic.html
ce9c101bbebef449d432567b9a29e9f9 *tests/testthat/template-document.html
bd23b1f0bd8705c3fe39c9f537cd1305 *tests/testthat/test-deps.r
f619582da6617e70858b2c462f956f9b *tests/testthat/test-tags.r
2d57750590f71f1bb6a96604a05a7d23 *tests/testthat/test-template.R
htmltools/DESCRIPTION 0000644 0001751 0000144 00000001075 13100571072 014022 0 ustar hornik users Package: htmltools
Type: Package
Title: Tools for HTML
Version: 0.3.6
Date: 2017-04-26
Author: RStudio, Inc.
Maintainer: Joe Cheng
Description: Tools for HTML generation and output.
Depends: R (>= 2.14.1)
Imports: utils, digest, Rcpp
Suggests: markdown, testthat
Enhances: knitr
License: GPL (>= 2)
URL: https://github.com/rstudio/htmltools
BugReports: https://github.com/rstudio/htmltools/issues
RoxygenNote: 6.0.1
LinkingTo: Rcpp
NeedsCompilation: yes
Packaged: 2017-04-27 00:04:32 UTC; jcheng
Repository: CRAN
Date/Publication: 2017-04-28 07:41:46 UTC
htmltools/man/ 0000755 0001751 0000144 00000000000 13100230764 013064 5 ustar hornik users htmltools/man/knitr_methods.Rd 0000644 0001751 0000144 00000001041 13100232577 016225 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/tags.R
\name{knitr_methods}
\alias{knitr_methods}
\alias{knit_print.shiny.tag}
\alias{knit_print.html}
\alias{knit_print.shiny.tag.list}
\title{Knitr S3 methods}
\usage{
knit_print.shiny.tag(x, ...)
knit_print.html(x, ...)
knit_print.shiny.tag.list(x, ...)
}
\arguments{
\item{x}{Object to knit_print}
\item{...}{Additional knit_print arguments}
}
\description{
These S3 methods are necessary to allow HTML tags to print themselves in
knitr/rmarkdown documents.
}
htmltools/man/browsable.Rd 0000644 0001751 0000144 00000001653 13100232577 015344 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/html_print.R
\name{browsable}
\alias{browsable}
\alias{is.browsable}
\title{Make an HTML object browsable}
\usage{
browsable(x, value = TRUE)
is.browsable(x)
}
\arguments{
\item{x}{The object to make browsable or not.}
\item{value}{Whether the object should be considered browsable.}
}
\value{
\code{browsable} returns \code{x} with an extra attribute to indicate
that the value is browsable.
\code{is.browsable} returns \code{TRUE} if the value is browsable, or
\code{FALSE} if not.
}
\description{
By default, HTML objects display their HTML markup at the console when
printed. \code{browsable} can be used to make specific objects render as HTML
by default when printed at the console.
}
\details{
You can override the default browsability of an HTML object by explicitly
passing \code{browse = TRUE} (or \code{FALSE}) to the \code{print} function.
}
htmltools/man/htmlEscape.Rd 0000644 0001751 0000144 00000000771 13100232577 015451 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/html_escape.R
\name{htmlEscape}
\alias{htmlEscape}
\title{Escape HTML entities}
\usage{
htmlEscape(text, attribute = FALSE)
}
\arguments{
\item{text}{Text to escape}
\item{attribute}{Escape for use as an attribute value}
}
\value{
Character vector with escaped text.
}
\description{
Escape HTML entities contained in a character vector so that it can be safely
included as text or an attribute value within an HTML document
}
htmltools/man/include.Rd 0000644 0001751 0000144 00000002460 13100232577 015004 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/tags.R
\name{include}
\alias{include}
\alias{includeHTML}
\alias{includeText}
\alias{includeMarkdown}
\alias{includeCSS}
\alias{includeScript}
\title{Include Content From a File}
\usage{
includeHTML(path)
includeText(path)
includeMarkdown(path)
includeCSS(path, ...)
includeScript(path, ...)
}
\arguments{
\item{path}{The path of the file to be included. It is highly recommended to
use a relative path (the base path being the Shiny application directory),
not an absolute path.}
\item{...}{Any additional attributes to be applied to the generated tag.}
}
\description{
Load HTML, text, or rendered Markdown from a file and turn into HTML.
}
\details{
These functions provide a convenient way to include an extensive amount of
HTML, textual, Markdown, CSS, or JavaScript content, rather than using a
large literal R string.
}
\note{
\code{includeText} escapes its contents, but does no other processing.
This means that hard breaks and multiple spaces will be rendered as they
usually are in HTML: as a single space character. If you are looking for
preformatted text, wrap the call with \code{\link{pre}}, or consider using
\code{includeMarkdown} instead.
The \code{includeMarkdown} function requires the \code{markdown}
package.
}
htmltools/man/save_html.Rd 0000644 0001751 0000144 00000001056 13100232577 015343 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/html_print.R
\name{save_html}
\alias{save_html}
\title{Save an HTML object to a file}
\usage{
save_html(html, file, background = "white", libdir = "lib")
}
\arguments{
\item{html}{HTML content to print}
\item{file}{File to write content to}
\item{background}{Background color for web page}
\item{libdir}{Directory to copy dependenies to}
}
\description{
Save the specified HTML object to a file, copying all of it's
dependencies to the directory specified via \code{libdir}.
}
htmltools/man/resolveDependencies.Rd 0000644 0001751 0000144 00000001462 13100232577 017350 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/tags.R
\name{resolveDependencies}
\alias{resolveDependencies}
\title{Resolve a list of dependencies}
\usage{
resolveDependencies(dependencies, resolvePackageDir = TRUE)
}
\arguments{
\item{dependencies}{A list of \code{\link{htmlDependency}} objects.}
\item{resolvePackageDir}{Whether to resolve the relative path to an absolute
path via \code{\link{system.file}} when the \code{package} attribute is
present in a dependency object.}
}
\value{
dependencies A list of \code{\link{htmlDependency}} objects with
redundancies removed.
}
\description{
Given a list of dependencies, removes any redundant dependencies (based on
name equality). If multiple versions of a dependency are found, the copy with
the latest version number is used.
}
htmltools/man/tag.Rd 0000644 0001751 0000144 00000004040 13100232577 014130 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/tags.R
\name{tag}
\alias{tag}
\alias{tagList}
\alias{tagAppendAttributes}
\alias{tagHasAttribute}
\alias{tagGetAttribute}
\alias{tagAppendChild}
\alias{tagAppendChildren}
\alias{tagSetChildren}
\alias{tag}
\title{HTML Tag Object}
\usage{
tagList(...)
tagAppendAttributes(tag, ...)
tagHasAttribute(tag, attr)
tagGetAttribute(tag, attr)
tagAppendChild(tag, child)
tagAppendChildren(tag, ..., list = NULL)
tagSetChildren(tag, ..., list = NULL)
tag(`_tag_name`, varArgs)
}
\arguments{
\item{...}{Unnamed items that comprise this list of tags.}
\item{tag}{A tag to append child elements to.}
\item{attr}{The name of an attribute.}
\item{child}{A child element to append to a parent tag.}
\item{list}{An optional list of elements. Can be used with or instead of the
\code{...} items.}
\item{_tag_name}{HTML tag name}
\item{varArgs}{List of attributes and children of the element. Named list
items become attributes, and unnamed list items become children. Valid
children are tags, single-character character vectors (which become text
nodes), and raw HTML (see \code{\link{HTML}}). You can also pass lists that
contain tags, text nodes, and HTML.}
}
\value{
An HTML tag object that can be rendered as HTML using
\code{\link{as.character}()}.
}
\description{
\code{tag()} creates an HTML tag definition. Note that all of the valid HTML5
tags are already defined in the \code{\link{tags}} environment so these
functions should only be used to generate additional tags.
\code{tagAppendChild()} and \code{tagList()} are for supporting package
authors who wish to create their own sets of tags; see the contents of
bootstrap.R for examples.
}
\examples{
tagList(tags$h1("Title"),
tags$h2("Header text"),
tags$p("Text here"))
# Can also convert a regular list to a tagList (internal data structure isn't
# exactly the same, but when rendered to HTML, the output is the same).
x <- list(tags$h1("Title"),
tags$h2("Header text"),
tags$p("Text here"))
tagList(x)
}
htmltools/man/validateCssUnit.Rd 0000644 0001751 0000144 00000002207 13100232577 016462 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/tags.R
\name{validateCssUnit}
\alias{validateCssUnit}
\title{Validate proper CSS formatting of a unit}
\usage{
validateCssUnit(x)
}
\arguments{
\item{x}{The unit to validate. Will be treated as a number of pixels if a
unit is not specified.}
}
\value{
A properly formatted CSS unit of length, if possible. Otherwise, will
throw an error.
}
\description{
Checks that the argument is valid for use as a CSS unit of length.
}
\details{
\code{NULL} and \code{NA} are returned unchanged.
Single element numeric vectors are returned as a character vector with the
number plus a suffix of \code{"px"}.
Single element character vectors must be \code{"auto"} or \code{"inherit"},
or a number. If the number has a suffix, it must be valid: \code{px},
\code{\%}, \code{em}, \code{pt}, \code{in}, \code{cm}, \code{mm}, \code{ex},
\code{pc}, \code{vh}, \code{vw}, \code{vmin}, or \code{vmax}.
If the number has no suffix, the suffix \code{"px"} is appended.
Any other value will cause an error to be thrown.
}
\examples{
validateCssUnit("10\%")
validateCssUnit(400) #treated as '400px'
}
htmltools/man/builder.Rd 0000644 0001751 0000144 00000003252 13100232577 015007 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/tags.R
\name{builder}
\alias{builder}
\alias{tags}
\alias{p}
\alias{h1}
\alias{h2}
\alias{h3}
\alias{h4}
\alias{h5}
\alias{h6}
\alias{a}
\alias{br}
\alias{div}
\alias{span}
\alias{pre}
\alias{code}
\alias{img}
\alias{strong}
\alias{em}
\alias{hr}
\title{HTML Builder Functions}
\usage{
tags
p(...)
h1(...)
h2(...)
h3(...)
h4(...)
h5(...)
h6(...)
a(...)
br(...)
div(...)
span(...)
pre(...)
code(...)
img(...)
strong(...)
em(...)
hr(...)
}
\arguments{
\item{...}{Attributes and children of the element. Named arguments become
attributes, and positional arguments become children. Valid children are
tags, single-character character vectors (which become text nodes), raw
HTML (see \code{\link{HTML}}), and \code{html_dependency} objects. You can
also pass lists that contain tags, text nodes, or HTML.}
}
\description{
Simple functions for constructing HTML documents.
}
\details{
The \code{tags} environment contains convenience functions for all valid
HTML5 tags. To generate tags that are not part of the HTML5 specification,
you can use the \code{\link{tag}()} function.
Dedicated functions are available for the most common HTML tags that do not
conflict with common R functions.
The result from these functions is a tag object, which can be converted using
\code{\link{as.character}()}.
}
\examples{
doc <- tags$html(
tags$head(
tags$title('My first page')
),
tags$body(
h1('My first heading'),
p('My first paragraph, with some ',
strong('bold'),
' text.'),
div(id='myDiv', class='simpleDiv',
'Here is a div with some attributes.')
)
)
cat(as.character(doc))
}
htmltools/man/css.Rd 0000644 0001751 0000144 00000003232 13100232577 014147 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/tags.R
\name{css}
\alias{css}
\title{CSS string helper}
\usage{
css(..., collapse_ = "")
}
\arguments{
\item{...}{Named style properties, where the name is the property name and
the argument is the property value. See Details for conversion rules.}
\item{collapse_}{(Note that the parameter name has a trailing underscore
character.) Character to use to collapse properties into a single string;
likely \code{""} (the default) for style attributes, and either \code{"\n"}
or \code{NULL} for style blocks.}
}
\description{
Convenience function for building CSS style declarations (i.e. the string
that goes into a style attribute, or the parts that go inside curly braces in
a full stylesheet).
}
\details{
CSS uses \code{'-'} (minus) as a separator character in property names, but
this is an inconvenient character to use in an R function argument name.
Instead, you can use \code{'.'} (period) and/or \code{'_'} (underscore) as
separator characters. For example, \code{css(font.size = "12px")} yields
\code{"font-size:12px;"}.
To mark a property as \code{!important}, add a \code{'!'} character to the end
of the property name. (Since \code{'!'} is not normally a character that can be
used in an identifier in R, you'll need to put the name in double quotes or
backticks.)
Argument values will be converted to strings using
\code{paste(collapse = " ")}. Any property with a value of \code{NULL} or
\code{""} (after paste) will be dropped.
}
\examples{
padding <- 6
css(
font.family = "Helvetica, sans-serif",
margin = paste0(c(10, 20, 10, 20), "px"),
"padding!" = if (!is.null(padding)) padding
)
}
htmltools/man/copyDependencyToDir.Rd 0000644 0001751 0000144 00000002651 13100232577 017276 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/html_dependency.R
\name{copyDependencyToDir}
\alias{copyDependencyToDir}
\title{Copy an HTML dependency to a directory}
\usage{
copyDependencyToDir(dependency, outputDir, mustWork = TRUE)
}
\arguments{
\item{dependency}{A single HTML dependency object.}
\item{outputDir}{The directory in which a subdirectory should be created for
this dependency.}
\item{mustWork}{If \code{TRUE} and \code{dependency} does not point to a
directory on disk (but rather a URL location), an error is raised. If
\code{FALSE} then non-disk dependencies are returned without modification.}
}
\value{
The dependency with its \code{src} value updated to the new
location's absolute path.
}
\description{
Copies an HTML dependency to a subdirectory of the given directory. The
subdirectory name will be \emph{name}-\emph{version} (for example,
"outputDir/jquery-1.11.0"). You may set \code{options(htmltools.dir.version =
FALSE)} to suppress the version number in the subdirectory name.
}
\details{
In order for disk-based dependencies to work with static HTML files, it's
generally necessary to copy them to either the directory of the referencing
HTML file, or to a subdirectory of that directory. This function makes it
easier to perform that copy.
}
\seealso{
\code{\link{makeDependencyRelative}} can be used with the returned
value to make the path relative to a specific directory.
}
htmltools/man/htmlDependencies.Rd 0000644 0001751 0000144 00000003300 13100232577 016626 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/html_dependency.R
\name{htmlDependencies}
\alias{htmlDependencies}
\alias{htmlDependencies<-}
\alias{attachDependencies}
\title{HTML dependency metadata}
\usage{
htmlDependencies(x)
htmlDependencies(x) <- value
attachDependencies(x, value, append = FALSE)
}
\arguments{
\item{x}{An object which has (or should have) HTML dependencies.}
\item{value}{An HTML dependency, or a list of HTML dependencies.}
\item{append}{If FALSE (the default), replace any existing dependencies. If
TRUE, add the new dependencies to the existing ones.}
}
\description{
Gets or sets the HTML dependencies associated with an object (such as a tag).
}
\details{
\code{attachDependencies} provides an alternate syntax for setting
dependencies. It is similar to \code{local(\{htmlDependencies(x) <- value;
x\})}, except that if there are any existing dependencies,
\code{attachDependencies} will add to them, instead of replacing them.
As of htmltools 0.3.4, HTML dependencies can be attached without using
\code{attachDependencies}. Instead, they can be added inline, like a child
object of a tag or \code{\link{tagList}}.
}
\examples{
# Create a JavaScript dependency
dep <- htmlDependency("jqueryui", "1.11.4", c(href="shared/jqueryui"),
script = "jquery-ui.min.js")
# A CSS dependency
htmlDependency(
"font-awesome", "4.5.0", c(href="shared/font-awesome"),
stylesheet = "css/font-awesome.min.css"
)
# A few different ways to add the dependency to tag objects:
# Inline as a child of the div()
div("Code here", dep)
# Inline in a tagList
tagList(div("Code here"), dep)
# With attachDependencies
attachDependencies(div("Code here"), dep)
}
htmltools/man/HTML.Rd 0000644 0001751 0000144 00000001072 13100232577 014123 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/tags.R
\name{HTML}
\alias{HTML}
\title{Mark Characters as HTML}
\usage{
HTML(text, ...)
}
\arguments{
\item{text}{The text value to mark with HTML}
\item{...}{Any additional values to be converted to character and
concatenated together}
}
\value{
The same value, but marked as HTML.
}
\description{
Marks the given text as HTML, which means the \link{tag} functions will know
not to perform HTML escaping on it.
}
\examples{
el <- div(HTML("I like turtles"))
cat(as.character(el))
}
htmltools/man/renderTags.Rd 0000644 0001751 0000144 00000003152 13100232577 015456 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/tags.R
\name{renderTags}
\alias{renderTags}
\alias{doRenderTags}
\title{Render tags into HTML}
\usage{
renderTags(x, singletons = character(0), indent = 0)
doRenderTags(x, indent = 0)
}
\arguments{
\item{x}{Tag object(s) to render}
\item{singletons}{A list of \link{singleton} signatures to consider already
rendered; any matching singletons will be dropped instead of rendered.
(This is useful (only?) for incremental rendering.)}
\item{indent}{Initial indent level, or \code{FALSE} if no indentation should
be used.}
}
\value{
\code{renderTags} returns a list with the following variables:
\describe{
\item{\code{head}}{An \code{\link{HTML}} string that should be included in
\code{}.
}
\item{\code{singletons}}{Character vector of singleton signatures that are
known after rendering.
}
\item{\code{dependencies}}{A list of \link[=resolveDependencies]{resolved}
\code{\link{htmlDependency}} objects.
}
\item{\code{html}}{An \code{\link{HTML}} string that represents the main
HTML that was rendered.
}
}
\code{doRenderTags} returns a simple \code{\link{HTML}} string.
}
\description{
Renders tags (and objects that can be converted into tags using
\code{\link{as.tags}}) into HTML. (Generally intended to be called from web
framework libraries, not directly by most users--see
\code{\link{print.html}(browse=TRUE)} for higher level rendering.)
}
\details{
\code{doRenderTags} is intended for very low-level use; it ignores
singleton, head, and dependency handling, and simply renders the given tag
objects as HTML.
}
htmltools/man/renderDependencies.Rd 0000644 0001751 0000144 00000001641 13100232577 017147 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/html_dependency.R
\name{renderDependencies}
\alias{renderDependencies}
\title{Create HTML for dependencies}
\usage{
renderDependencies(dependencies, srcType = c("href", "file"),
encodeFunc = urlEncodePath, hrefFilter = identity)
}
\arguments{
\item{dependencies}{A list of \code{htmlDependency} objects.}
\item{srcType}{The type of src paths to use; valid values are \code{file} or
\code{href}.}
\item{encodeFunc}{The function to use to encode the path part of a URL. The
default should generally be used.}
\item{hrefFilter}{A function used to transform the final, encoded URLs of
script and stylsheet files. The default should generally be used.}
}
\value{
An \code{\link{HTML}} object suitable for inclusion in the head of an
HTML document.
}
\description{
Create the appropriate HTML markup for including dependencies in an HTML
document.
}
htmltools/man/htmlDependency.Rd 0000644 0001751 0000144 00000007265 13100232577 016334 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/html_dependency.R
\name{htmlDependency}
\alias{htmlDependency}
\title{Define an HTML dependency}
\usage{
htmlDependency(name, version, src, meta = NULL, script = NULL,
stylesheet = NULL, head = NULL, attachment = NULL, package = NULL,
all_files = TRUE)
}
\arguments{
\item{name}{Library name}
\item{version}{Library version}
\item{src}{Unnamed single-element character vector indicating the full path
of the library directory. Alternatively, a named character string with one
or more elements, indicating different places to find the library; see
Details.}
\item{meta}{Named list of meta tags to insert into document head}
\item{script}{Script(s) to include within the document head (should be
specified relative to the \code{src} parameter).}
\item{stylesheet}{Stylesheet(s) to include within the document (should be
specified relative to the \code{src} parameter).}
\item{head}{Arbitrary lines of HTML to insert into the document head}
\item{attachment}{Attachment(s) to include within the document head. See
Details.}
\item{package}{An R package name to indicate where to find the \code{src}
directory when \code{src} is a relative path (see
\code{\link{resolveDependencies}}).}
\item{all_files}{Whether all files under the \code{src} directory are
dependency files. If \code{FALSE}, only the files specified in
\code{script}, \code{stylesheet}, and \code{attachment} are treated as
dependency files.}
}
\value{
An object that can be included in a list of dependencies passed to
\code{\link{attachDependencies}}.
}
\description{
Define an HTML dependency (i.e. CSS and/or JavaScript bundled in a
directory). HTML dependencies make it possible to use libraries like jQuery,
Bootstrap, and d3 in a more composable and portable way than simply using
script, link, and style tags.
}
\details{
Each dependency can be located on the filesystem, at a relative or
absolute URL, or both. The location types are indicated using the names of
the \code{src} character vector: \code{file} for filesystem directory,
\code{href} for URL. For example, a dependency that was both on disk and at
a URL might use \code{src = c(file=filepath, href=url)}.
\code{attachment} can be used to make the indicated files available to the
JavaScript on the page via URL. For each element of \code{attachment}, an
element \code{} is inserted, where \code{DEPNAME} is \code{name}. The value of
\code{ATTACHINDEX} depends on whether \code{attachment} is named or not; if
so, then it's the name of the element, and if not, it's the 1-based index
of the element. JavaScript can retrieve the URL using something like
\code{document.getElementById(depname + "-" + index + "-attachment").href}.
Note that depending on the rendering context, the runtime value of the href
may be an absolute, relative, or data URI.
\code{htmlDependency} should not be called from the top-level of a package
namespace with absolute paths (or with paths generated by
\code{system.file()}) and have the result stored in a variable. This is
because, when a binary package is built, R will run \code{htmlDependency}
and store the path from the building machine's in the package. This path is
likely to differ from the correct path on a machine that downloads and
installs the binary package. If there are any absolute paths, instead of
calling \code{htmlDependency} at build-time, it should be called at
run-time. This can be done by wrapping the \code{htmlDependency} call in a
function.
}
\seealso{
Use \code{\link{attachDependencies}} to associate a list of
dependencies with the HTML it belongs with.
}
htmltools/man/singleton_tools.Rd 0000644 0001751 0000144 00000002355 13100232577 016606 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/tags.R
\name{singleton_tools}
\alias{singleton_tools}
\alias{surroundSingletons}
\alias{takeSingletons}
\title{Singleton manipulation functions}
\usage{
surroundSingletons(ui)
takeSingletons(ui, singletons = character(0), desingleton = TRUE)
}
\arguments{
\item{ui}{Tag object or lists of tag objects. See \link{builder} topic.}
\item{singletons}{Character vector of singleton signatures that have already
been encountered (i.e. returned from previous calls to
\code{takeSingletons}).}
\item{desingleton}{Logical value indicating whether singletons that are
encountered should have the singleton attribute removed.}
}
\value{
\code{surroundSingletons} preprocesses a tag object by changing any
singleton X into X'
where sig is the sha1 of X, and X' is X minus the singleton attribute.
\code{takeSingletons} returns a list with the elements \code{ui} (the
processed tag objects with any duplicate singleton objects removed) and
\code{singletons} (the list of known singleton signatures).
}
\description{
Functions for manipulating \code{\link{singleton}} objects in tag
hierarchies. Intended for framework authors.
}
htmltools/man/htmlTemplate.Rd 0000644 0001751 0000144 00000002101 13100232577 016011 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/template.R
\name{htmlTemplate}
\alias{htmlTemplate}
\title{Process an HTML template}
\usage{
htmlTemplate(filename = NULL, ..., text_ = NULL, document_ = "auto")
}
\arguments{
\item{filename}{Path to an HTML template file. Incompatible with
\code{text_}.}
\item{...}{Variable values to use when processing the template.}
\item{text_}{A string to use as the template, instead of a file. Incompatible
with \code{filename}.}
\item{document_}{Is this template a complete HTML document (\code{TRUE}), or
a fragment of HTML that is to be inserted into an HTML document
(\code{FALSE})? With \code{"auto"} (the default), auto-detect by searching
for the string \code{""} within the template.}
}
\description{
Process an HTML template and return a tagList object. If the template is a
complete HTML document, then the returned object will also have class
\code{html_document}, and can be passed to the function
\code{\link{renderDocument}} to get the final HTML text.
}
\seealso{
\code{\link{renderDocument}}
}
htmltools/man/urlEncodePath.Rd 0000644 0001751 0000144 00000000617 13100232577 016120 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/html_dependency.R
\name{urlEncodePath}
\alias{urlEncodePath}
\title{Encode a URL path}
\usage{
urlEncodePath(x)
}
\arguments{
\item{x}{A character vector.}
}
\description{
Encode characters in a URL path. This is the same as
\code{\link[utils]{URLencode}} with \code{reserved = TRUE} except that
\code{/} is preserved.
}
htmltools/man/print.html.Rd 0000644 0001751 0000144 00000001370 13100232577 015457 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/tags.R
\name{print.shiny.tag}
\alias{print.shiny.tag}
\alias{print.html}
\title{Print method for HTML/tags}
\usage{
\method{print}{shiny.tag}(x, browse = is.browsable(x), ...)
\method{print}{html}(x, ..., browse = is.browsable(x))
}
\arguments{
\item{x}{The value to print.}
\item{browse}{If \code{TRUE}, the HTML will be rendered and displayed in a
browser (or possibly another HTML viewer supplied by the environment via
the \code{viewer} option). If \code{FALSE} then the HTML object's markup
will be rendered at the console.}
\item{...}{Additional arguments passed to print.}
}
\description{
S3 method for printing HTML that prints markup or renders HTML in a web
browser.
}
htmltools/man/html_print.Rd 0000644 0001751 0000144 00000001333 13100232577 015537 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/html_print.R
\name{html_print}
\alias{html_print}
\title{Implementation of the print method for HTML}
\usage{
html_print(html, background = "white", viewer = getOption("viewer",
utils::browseURL))
}
\arguments{
\item{html}{HTML content to print}
\item{background}{Background color for web page}
\item{viewer}{A function to be called with the URL or path to the generated
HTML page. Can be \code{NULL}, in which case no viewer will be invoked.}
}
\value{
Invisibly returns the URL or path of the generated HTML page.
}
\description{
Convenience method that provides an implementation of the
\code{\link[base:print]{print}} method for HTML content.
}
htmltools/man/makeDependencyRelative.Rd 0000644 0001751 0000144 00000002054 13100232577 017770 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/html_dependency.R
\name{makeDependencyRelative}
\alias{makeDependencyRelative}
\title{Make an absolute dependency relative}
\usage{
makeDependencyRelative(dependency, basepath, mustWork = TRUE)
}
\arguments{
\item{dependency}{A single HTML dependency with an absolute path.}
\item{basepath}{The path to the directory that \code{dependency} should be
made relative to.}
\item{mustWork}{If \code{TRUE} and \code{dependency} does not point to a
directory on disk (but rather a URL location), an error is raised. If
\code{FALSE} then non-disk dependencies are returned without modification.}
}
\value{
The dependency with its \code{src} value updated to the new
location's relative path.
If \code{baspath} did not appear to be a parent directory of the dependency's
directory, an error is raised (regardless of the value of \code{mustWork}).
}
\description{
Change a dependency's absolute path to be relative to one of its parent
directories.
}
\seealso{
\code{\link{copyDependencyToDir}}
}
htmltools/man/findDependencies.Rd 0000644 0001751 0000144 00000001020 13100232577 016577 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/tags.R
\name{findDependencies}
\alias{findDependencies}
\title{Collect attached dependencies from HTML tag object}
\usage{
findDependencies(tags, tagify = TRUE)
}
\arguments{
\item{tags}{A tag-like object to search for dependencies.}
\item{tagify}{Whether to tagify the input before searching for dependencies.}
}
\value{
A list of \code{\link{htmlDependency}} objects.
}
\description{
Walks a hierarchy of tags looking for attached dependencies.
}
htmltools/man/withTags.Rd 0000644 0001751 0000144 00000002066 13100232577 015155 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/tags.R
\name{withTags}
\alias{withTags}
\title{Evaluate an expression using \code{tags}}
\usage{
withTags(code)
}
\arguments{
\item{code}{A set of tags.}
}
\description{
This function makes it simpler to write HTML-generating code. Instead of
needing to specify \code{tags} each time a tag function is used, as in
\code{tags$div()} and \code{tags$p()}, code inside \code{withTags} is
evaluated with \code{tags} searched first, so you can simply use
\code{div()} and \code{p()}.
}
\details{
If your code uses an object which happens to have the same name as an
HTML tag function, such as \code{source()} or \code{summary()}, it will call
the tag function. To call the intended (non-tags function), specify the
namespace, as in \code{base::source()} or \code{base::summary()}.
}
\examples{
# Using tags$ each time
tags$div(class = "myclass",
tags$h3("header"),
tags$p("text")
)
# Equivalent to above, but using withTags
withTags(
div(class = "myclass",
h3("header"),
p("text")
)
)
}
htmltools/man/suppressDependencies.Rd 0000644 0001751 0000144 00000001214 13100232577 017550 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/html_dependency.R
\name{suppressDependencies}
\alias{suppressDependencies}
\title{Suppress web dependencies}
\usage{
suppressDependencies(...)
}
\arguments{
\item{...}{Names of the dependencies to suppress. For example,
\code{"jquery"} or \code{"bootstrap"}.}
}
\description{
This suppresses one or more web dependencies. It is meant to be used when a
dependency (like a JavaScript or CSS file) is declared in raw HTML, in an
HTML template.
}
\seealso{
\code{\link{htmlTemplate}} for more information about using HTML
templates.
\code{\link[htmltools]{htmlDependency}}
}
htmltools/man/subtractDependencies.Rd 0000644 0001751 0000144 00000002276 13100232577 017524 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/tags.R
\name{subtractDependencies}
\alias{subtractDependencies}
\title{Subtract dependencies}
\usage{
subtractDependencies(dependencies, remove, warnOnConflict = TRUE)
}
\arguments{
\item{dependencies}{A list of \code{\link{htmlDependency}} objects from which
dependencies should be removed.}
\item{remove}{A list of \code{\link{htmlDependency}} objects indicating which
dependencies should be removed, or a character vector indicating dependency
names.}
\item{warnOnConflict}{If \code{TRUE}, a warning is emitted for each
dependency that is removed if the corresponding dependency in \code{remove}
has a lower version number. Has no effect if \code{remove} is provided as a
character vector.}
}
\value{
A list of \code{\link{htmlDependency}} objects that don't intersect
with \code{remove}.
}
\description{
Remove a set of dependencies from another list of dependencies. The set of
dependencies to remove can be expressed as either a character vector or a
list; if the latter, a warning can be emitted if the version of the
dependency being removed is later than the version of the dependency object
that is causing the removal.
}
htmltools/man/singleton.Rd 0000644 0001751 0000144 00000001207 13100232577 015361 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/tags.R
\name{singleton}
\alias{singleton}
\alias{is.singleton}
\title{Include content only once}
\usage{
singleton(x, value = TRUE)
is.singleton(x)
}
\arguments{
\item{x}{A \code{\link{tag}}, text, \code{\link{HTML}}, or list.}
\item{value}{Whether the object should be a singleton.}
}
\description{
Use \code{singleton} to wrap contents (tag, text, HTML, or lists) that should
be included in the generated document only once, yet may appear in the
document-generating code more than once. Only the first appearance of the
content (in document order) will be used.
}
htmltools/man/htmlPreserve.Rd 0000644 0001751 0000144 00000004447 13100232577 016050 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/tags.R
\name{htmlPreserve}
\alias{htmlPreserve}
\alias{extractPreserveChunks}
\alias{restorePreserveChunks}
\title{Preserve HTML regions}
\usage{
htmlPreserve(x)
extractPreserveChunks(strval)
restorePreserveChunks(strval, chunks)
}
\arguments{
\item{x}{A character vector of HTML to be preserved.}
\item{strval}{Input string from which to extract/restore chunks.}
\item{chunks}{The \code{chunks} element of the return value of
\code{extractPreserveChunks}.}
}
\value{
\code{htmlPreserve} returns a single-element character vector with
"magic" HTML comments surrounding the original text (unless the original
text was empty, in which case an empty string is returned).
\code{extractPreserveChunks} returns a list with two named elements:
\code{value} is the string with the regions replaced, and \code{chunks} is
a named character vector where the names are the IDs and the values are the
regions that were extracted.
\code{restorePreserveChunks} returns a character vector with the
chunk IDs replaced with their original values.
}
\description{
Use "magic" HTML comments to protect regions of HTML from being modified by
text processing tools.
}
\details{
Text processing tools like markdown and pandoc are designed to turn
human-friendly markup into common output formats like HTML. This works well
for most prose, but components that generate their own HTML may break if
their markup is interpreted as the input language. The \code{htmlPreserve}
function is used to mark regions of an input document as containing pure HTML
that must not be modified. This is achieved by substituting each such region
with a benign but unique string before processing, and undoing those
substitutions after processing.
}
\examples{
# htmlPreserve will prevent ""
# from getting an tag inserted in the middle
markup <- paste(sep = "\\n",
"This is *emphasized* text in markdown.",
htmlPreserve(""),
"Here is some more *emphasized text*."
)
extracted <- extractPreserveChunks(markup)
markup <- extracted$value
# Just think of this next line as Markdown processing
output <- gsub("\\\\*(.*?)\\\\*", "\\\\1", markup)
output <- restorePreserveChunks(output, extracted$chunks)
output
}
htmltools/man/as.tags.Rd 0000644 0001751 0000144 00000000722 13100232577 014720 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/tags.R
\name{as.tags}
\alias{as.tags}
\title{Convert a value to tags}
\usage{
as.tags(x, ...)
}
\arguments{
\item{x}{Object to be converted.}
\item{...}{Any additional parameters.}
}
\description{
An S3 method for converting arbitrary values to a value that can be used as
the child of a tag or \code{tagList}. The default implementation simply calls
\code{\link[base]{as.character}}.
}
htmltools/man/renderDocument.Rd 0000644 0001751 0000144 00000002556 13100232577 016345 0 ustar hornik users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/template.R
\name{renderDocument}
\alias{renderDocument}
\title{Render an html_document object}
\usage{
renderDocument(x, deps = NULL, processDep = identity)
}
\arguments{
\item{x}{An object of class \code{html_document}, typically generated by the
\code{\link{htmlTemplate}} function.}
\item{deps}{Any extra web dependencies to add to the html document. This can
be an object created by \code{\link{htmlDependency}}, or a list of such
objects. These dependencies will be added first, before other dependencies.}
\item{processDep}{A function that takes a "raw" html_dependency object and
does further processing on it. For example, when \code{renderDocument} is
called from Shiny, the function \code{\link[shiny]{createWebDependency}} is
used; it modifies the href and tells Shiny to serve a particular path on
the filesystem.}
}
\description{
This function renders \code{html_document} objects, and returns a string with
the final HTML content. It calls the \code{\link{renderTags}} function to
convert any shiny.tag objects to HTML. It also finds any any web dependencies
(created by \code{\link{htmlDependency}}) that are attached to the tags, and
inserts those. To do the insertion, this function finds the string
\code{""} in the document, and replaces it with the web
dependencies.
}