diff --git a/DESCRIPTION b/DESCRIPTION index d7ba2d5f22..af22161baa 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: rmarkdown Title: Dynamic Documents for R -Version: 2.21.4.9000 +Version: 2.24.1.9000 Authors@R: c( person("JJ", "Allaire", , "jj@posit.co", role = "aut"), person("Yihui", "Xie", , "xie@yihui.name", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-0645-5666")), @@ -30,7 +30,7 @@ Authors@R: c( person("Ruben", "Arslan", , "ruben.arslan@uni-goettingen.de", role = "ctb"), person("Sergio", "Oller", role = "ctb"), person(given = "Posit Software, PBC", role = c("cph", "fnd")), - person(, "jQuery UI contributors", role = c("ctb", "cph"), comment = "jQuery UI library; authors listed in inst/rmd/h/jqueryui-AUTHORS.txt"), + person(, "jQuery UI contributors", role = c("ctb", "cph"), comment = "jQuery UI library; authors listed in inst/rmd/h/jqueryui/AUTHORS.txt"), person("Mark", "Otto", role = "ctb", comment = "Bootstrap library"), person("Jacob", "Thornton", role = "ctb", comment = "Bootstrap library"), person(, "Bootstrap contributors", role = "ctb", comment = "Bootstrap library"), @@ -84,6 +84,7 @@ Suggests: testthat (>= 3.0.3), tibble, vctrs, + cleanrmd, withr (>= 2.4.2) VignetteBuilder: knitr Config/Needs/website: rstudio/quillt, pkgdown diff --git a/NAMESPACE b/NAMESPACE index 2109863629..d6acf4a8e7 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,7 @@ # Generated by roxygen2: do not edit by hand S3method(knit_print,grouped_df) +S3method(knit_print,output_format_dependency) S3method(knit_print,rowwise_df) S3method(knit_print,tbl_sql) S3method(prepare_evaluate_output,default) @@ -57,6 +58,7 @@ export(navbar_html) export(navbar_links_html) export(odt_document) export(output_format) +export(output_format_dependency) export(output_metadata) export(paged_table) export(pandoc_available) diff --git a/NEWS.md b/NEWS.md index 4dab568796..90f086fec9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,12 +1,42 @@ +rmarkdown 2.25 +================================================================================ + + + +rmarkdown 2.24 +================================================================================ + +- Fixed `file_scope` being lost when extending output formats that considers the `file_scope` using `output_format()`. Merge behavior is to apply overlay `file_scope` function onto the result of `base_format`'s `file_scope` function. This implies that `file_scope` gains second argument which receives the returned values of the base `file_scope` (thanks, @atusy, #2488). + +- Added `output_format_dependency()` which allows extending output format from within chunks (thanks, @atusy, #2462) + +- Fix an issue with shiny prerendered document where dependencies context were written twice leasing to parsing error (thanks, @gadenbuie, rstudio/learn#597, #2500). + + +rmarkdown 2.23 +================================================================================ + +- `find_external_resources()` works with formats defining there own `theme` argument, like `cleanrmd::html_document_clean()`, not related to **bslib** supports (thanks, @gadenbuie, #2493, r-lib/pkgdown#2319). + +- Fixed version number comparison problems as requested by CRAN. + + rmarkdown 2.22 ================================================================================ +- Using `css` with `.scss` and `.sass` file, or with a bslib theme, now works as expected with a shiny runtime (thanks, @cpsievert, #2443, #2447). + - Add a `pandoc_metadata_file_arg()` function to match Pandoc's CLI flag `--metadata-file`. - Mentions that **webshot** or **webshot2** is required to take screenshot of HTML widget. When not installed, an error message mentionning `always_allow_html: true` solution will be shown, but setting this is not the solution (quarto-dev/quarto-cli#4225). +- `html_dependency_jqueryui()` updated to 1.13.2 from version bundled in shiny (thanks, @daschnerm, #2477). + - Fix an issue with YAML header ending with a commented line containing incomplete yaml (thanks, @keithnewman, #2483). +- When code folding is enabled in `html_document()`, the text on the button to show the content has been changed from "Code" to "Show", because the content to show is not necessarily code, e.g., yihui/knitr#2227. + + rmarkdown 2.21 ================================================================================ diff --git a/R/context_document.R b/R/context_document.R index 83ce594b4a..48744ac459 100644 --- a/R/context_document.R +++ b/R/context_document.R @@ -1,11 +1,8 @@ #' Convert to a ConTeXt document #' -#' Format for converting from R Markdown to PDF using -#' \href{https://wiki.contextgarden.net/Main_Page}{ConTeXt}. +#' Format for converting from R Markdown to PDF using ConTeXt. #' -#' ConTeXt needs to be installed. To install the most recent version, see -#' \url{https://wiki.contextgarden.net/Installation}. A less recent version is -#' also available in TeX Live, you can install it with +#' ConTeXt needs to be installed, e.g., you can install it with #' \code{tinytex::tlmgr_install("context")}. #' #' R Markdown documents can have optional metadata that is used to generate a @@ -17,8 +14,8 @@ #' \href{https://pandoc.org/MANUAL.html#citations}{Bibliographies #' and Citations} article in the online documentation. #' @inheritParams pdf_document -#' @param context_path Path of the ConTeXt executable. If not provided, ConTeXt has -#' to be available from the \code{PATH} environment variable. +#' @param context_path Path of the ConTeXt executable. If not provided, ConTeXt +#' has to be available from the \code{PATH} environment variable. #' @param context_args Command line arguments passed to ConTeXt. #' @param ext Format of the output document (defaults to ".pdf"). #' @return R Markdown output format to pass to \code{\link{render}}. diff --git a/R/html_dependencies.R b/R/html_dependencies.R index 75656c0a97..01de78314d 100644 --- a/R/html_dependencies.R +++ b/R/html_dependencies.R @@ -26,7 +26,7 @@ html_dependency_jqueryui <- function() { htmlDependency( name = "jqueryui", - version = "1.11.4", + version = version_jqueryui, src = pkg_file("rmd/h/jqueryui"), script = "jquery-ui.min.js") } @@ -84,6 +84,7 @@ bootstrap_dependencies <- function(theme) { if (inherits(deps, "html_dependency")) list(deps) else deps } +# resolves boostrap theme for bslib compatibility resolve_theme <- function(theme) { # theme = NULL means no Bootstrap if (is.null(theme)) return(theme) @@ -153,6 +154,10 @@ theme_version <- function(theme) { substr(html_dependency_bootstrap("default")$version, 1, 1) } +needs_sass <- function(css) { + grepl("\\.s[ac]ss$", css) +} + # Create an HTML dependency for tocify #' @rdname html-dependencies diff --git a/R/html_document_base.R b/R/html_document_base.R index 96a100f301..8c5727c57c 100644 --- a/R/html_document_base.R +++ b/R/html_document_base.R @@ -99,7 +99,7 @@ html_document_base <- function(theme = NULL, # Process css files as Pandoc argument if not already been processed by bslib for (f in css) { - if (grepl("\\.s[ac]ss$", f)) { + if (needs_sass(f)) { if (!xfun::loadable("sass")) { stop2("Using `.sass` or `.scss` file in `css` argument requires the sass package.") } diff --git a/R/html_paged.R b/R/html_paged.R index 78aa50aa76..c6935a1b14 100644 --- a/R/html_paged.R +++ b/R/html_paged.R @@ -238,7 +238,7 @@ paged_table <- function(x, options = NULL) { x } -print.paged_df <- function(x) { +print.paged_df <- function(x, ...) { knitr::asis_output( paged_table_html(x, options = attr(x, "options")), meta = list( diff --git a/R/html_resources.R b/R/html_resources.R index c302f83ba3..c4aa4f68d0 100644 --- a/R/html_resources.R +++ b/R/html_resources.R @@ -55,7 +55,7 @@ find_external_resources <- function(input_file, encoding = 'UTF-8') { # ensure we're working with valid input ext <- tolower(xfun::file_ext(input_file)) if (!(ext %in% c("md", "rmd", "qmd", "html", "htm", "r", "css"))) { - stop("Resource discovery is only supported for R Markdown files or HTML files.") + stop("Resource discovery is only supported for R Markdown, Quarto files or HTML (and CSS) files.") } if (!file.exists(input_file)) { @@ -138,7 +138,7 @@ find_external_resources <- function(input_file, encoding = 'UTF-8') { # clean row names (they're not meaningful) rownames(discovered_resources) <- NULL - # convert paths from factors if necssary, and clean any redundant ./ leaders + # convert paths from factors if necessary, and clean any redundant ./ leaders discovered_resources$path <- as.character(discovered_resources$path) has_prefix <- grepl("^\\./", discovered_resources$path) discovered_resources$path[has_prefix] <- substring(discovered_resources$path[has_prefix], 3) @@ -216,6 +216,13 @@ discover_rmd_resources <- function(rmd_file, discover_single_resource) { output_render_files <- unlist(output_format[c( 'includes', 'pandoc_args', 'logo', 'reference_doc', 'reference_docx', 'template' )]) + resolved_theme <- tryCatch(resolve_theme(output_format[["theme"]]), error = function(e) NULL) + # css needs to be copied for sass or bslib processing in formate rendering + needed <- if (is_bs_theme(resolved_theme)) TRUE else { + needs_sass(output_format[['css']]) + } + output_render_files <- c(output_render_files, output_format[['css']][needed]) + lapply(output_render_files, discover_render_resource) } } diff --git a/R/html_vignette.R b/R/html_vignette.R index 0b528e3d2d..d6577ef546 100644 --- a/R/html_vignette.R +++ b/R/html_vignette.R @@ -107,7 +107,7 @@ html_vignette <- function(fig_width = 3, } vignette_pre_processor <- function(input_file, metadata = yaml_front_matter(input_file)) { - if (getRversion() < 3.6) + if (getRversion() < '3.6') return() if (!getOption(o <- 'rmarkdown.html_vignette.check_title', !xfun::is_R_CMD_check())) return() diff --git a/R/md_document.R b/R/md_document.R index f58a1671d4..10b263388a 100644 --- a/R/md_document.R +++ b/R/md_document.R @@ -157,7 +157,7 @@ adapt_md_variant <- function(variant) { gfm = , commonmark = , commonmark_x = { - if (pandoc_available(2.13)) { + if (pandoc_available("2.13")) { set_extension(variant_extensions, "yaml_metadata_block", FALSE) } else { # Unsupported extension before YAML 2.13 diff --git a/R/output_format.R b/R/output_format.R index d583becdca..8a5b79ada3 100644 --- a/R/output_format.R +++ b/R/output_format.R @@ -52,9 +52,11 @@ #' @param file_scope A function that will split markdown input to pandoc into #' multiple named files. This is useful when the caller has concatenated a set #' of Rmd files together (as \pkg{bookdown} does), and those files may need to -#' processed by pandoc using the \code{--file-scope} option. The function -#' should return a named list of files w/ \code{name} and \code{content} for -#' each file. +#' processed by pandoc using the \code{--file-scope} option. The first +#' argument is input file paths and the second is \code{NULL} or current file +#' scope which is a named list of files w/ \code{name} and \code{content} for +#' each file. The return is the new file scope. Also, the arguments should +#' include \code{...} for the future extensions. #' @param base_format An optional format to extend. #' @param allow_uptree_lib_dir Allow \code{lib_dir} output parameter not to #' be a descendent of the output directory. @@ -161,6 +163,27 @@ merge_post_processors <- function(base, } } +merge_file_scope <- function(base, + overlay) { + if (is.null(overlay)) { + return(base) + } + has_ellipsis <- "..." %in% names(formals(overlay)) + if (!has_ellipsis) { + warning("file_scope lacks ... as an argument. ", + "Otherwise, file_scope replaces file_scope without merging.") + } + if (is.null(base) || !has_ellipsis) { + return(overlay) + } + if (has_ellipsis) { + return(function(x, current_scope = NULL, ...) { + scope <- base(x, current_scope, ...) + overlay(x, scope, ...) + }) + } +} + # merges two output formats merge_output_formats <- function(base, overlay) { @@ -187,6 +210,7 @@ merge_output_formats <- function(base, overlay$intermediates_generator, c), post_processor = merge_post_processors(base$post_processor, overlay$post_processor), + file_scope = merge_file_scope(base$file_scope, overlay$file_scope), on_exit = merge_on_exit(base$on_exit, overlay$on_exit) ), class = "rmarkdown_output_format") @@ -813,3 +837,63 @@ citeproc_required <- function(yaml_front_matter, length(grep("^bibliography:\\s*$", input_lines)) > 0 ) } + +#' Define an R Markdown's output format dependency +#' +#' Define the dependency such as and pre/post-processors dynamically from +#' within chunks. This function shares some arguments with +#' \code{\link{output_format}}, but lacks the others because dependency +#' is resolved after \code{post_knit} and before \code{pre_processor}. +#' +#' @param name A dependency name. If some dependencies share the same name, +#' then only the first one will be attached. +#' @inheritParams output_format +#' @return An list of arguments with the "rmd_dependency" class. +#' @examples +#' # Add lua filters from within a chunk +#' output_format_dependency("lua_filter", pre_processor = function(...) { +#' pandoc_lua_filter_args(c("example1.lua", "example2.lua")) +#' }) +#' +#' @export +output_format_dependency <- function(name, + pandoc = list(), + pre_processor = NULL, + post_processor = NULL, + file_scope = NULL, + on_exit = NULL) { + # Some arguments are NULL + # to ensure inheriting the values from the base output format + structure(list(name = name, + knitr = NULL, # must be NULL because merge happens after knit + pandoc = pandoc, + pre_processor = pre_processor, + keep_md = NULL, + clean_supporting = NULL, + post_processor = post_processor, + file_scope = file_scope, + on_exit = on_exit), + class = "output_format_dependency") +} + +#' @export +knit_print.output_format_dependency <- function(x, ...) { + knitr::asis_output(list(), meta = list(x)) +} + +merge_output_format_dependency <- function(fmt, dep) { + dep$name <- NULL # remove to be consistent with arguments of output_format + dep$base_format <- fmt + do.call(output_format, dep) +} + +merge_output_format_dependencies <- function(fmt, deps) { + skip <- c() + for (d in deps) { + if (inherits(d, "output_format_dependency") && !isTRUE(skip[d$name])) { + skip[d$name] <- TRUE + fmt <- merge_output_format_dependency(fmt, d) + } + } + fmt +} diff --git a/R/render.R b/R/render.R index 9d73610d8c..f6f75b8424 100644 --- a/R/render.R +++ b/R/render.R @@ -840,6 +840,9 @@ render <- function(input, perf_timer_start("pre-processor") + if (has_dependencies(knit_meta, "output_format_dependency")) { + output_format <- merge_output_format_dependencies(output_format, knit_meta) + } # call any pre_processor if (!is.null(output_format$pre_processor)) { extra_args <- output_format$pre_processor(front_matter, @@ -1200,7 +1203,11 @@ resolve_df_print <- function(df_print) { output_metadata = knitr:::new_defaults() file_scope_split <- function(input, fun) { - inputs <- fun(input) + inputs <- if (length(formals(fun)) == 1L) { + fun(input) # for the backward compatibility + } else { + fun(input, NULL) # the second argument implies current file scope + } # file_scope_fun should split the input file in several # do nothing if not and return input file unsplited diff --git a/R/shiny_prerendered.R b/R/shiny_prerendered.R index 9c6a9f2d7b..d7889ea9f3 100644 --- a/R/shiny_prerendered.R +++ b/R/shiny_prerendered.R @@ -155,8 +155,7 @@ shiny_prerendered_html <- function(input_rmd, render_args) { # extract dependencies from html html_lines <- read_utf8(rendered_html) - dependencies_json <- shiny_prerendered_extract_context(html_lines, "dependencies") - dependencies <- jsonlite::unserializeJSON(dependencies_json) + dependencies <- shiny_prerendered_extract_context_serialized(html_lines, "dependencies") # resolve package paths (this will happen automatically for the # development version of htmltools but this isn't on CRAN yet) @@ -255,8 +254,14 @@ shiny_prerendered_prerender <- function( html_lines <- read_utf8(rendered_html) # check that all html dependencies exist - dependencies_json <- shiny_prerendered_extract_context(html_lines, "dependencies") - dependencies <- jsonlite::unserializeJSON(dependencies_json) + dependencies <- tryCatch( + shiny_prerendered_extract_context_serialized(html_lines, "dependencies"), + error = function(...) NULL + ) + if (is.null(dependencies)) { + # Pre-render needed: failed to parse deps from pre-rendered HTML + return(TRUE) + } pkgsSeen <- list() for (dep in dependencies) { @@ -291,8 +296,14 @@ shiny_prerendered_prerender <- function( # all html dependencies are accounted for # check for execution package version differences - execution_json <- shiny_prerendered_extract_context(html_lines, "execution_dependencies") - execution_info <- jsonlite::unserializeJSON(execution_json) + execution_info <- tryCatch( + shiny_prerendered_extract_context_serialized(html_lines, "execution_dependencies"), + error = function(...) NULL + ) + if (is.null(execution_info)) { + # Pre-render needed: failed to parse execution deps from pre-rendered HTML + return(TRUE) + } execution_pkg_names <- execution_info$packages$packages execution_pkg_versions <- execution_info$packages$version for (i in seq_along(execution_pkg_names)) { @@ -380,6 +391,16 @@ shiny_prerendered_append_dependencies <- function(input, # always UTF-8 shiny_prerendered_append_context(con, "execution_dependencies", execution_json) } +shiny_prerendered_extract_context_serialized <- function(html_lines, context = "dependencies") { + json_str <- shiny_prerendered_extract_context(html_lines, context) + json_str <- unique(json_str) + if (length(json_str) > 1) { + warning("Multiple ", context, " contexts found in prerendered HTML, using last.") + json_str <- json_str[length(json_str)] + } + jsonlite::unserializeJSON(json_str) +} + #' Clean prerendered content for the specified Rmd input file #' diff --git a/R/version_jqueryui.R b/R/version_jqueryui.R new file mode 100644 index 0000000000..5ae52ccbf0 --- /dev/null +++ b/R/version_jqueryui.R @@ -0,0 +1,2 @@ +# Generated by tools/updatejQueryUI.R; do not edit by hand +version_jqueryui <- "1.13.2" diff --git a/inst/rmd/h/jqueryui-AUTHORS.txt b/inst/rmd/h/jqueryui/AUTHORS.txt similarity index 83% rename from inst/rmd/h/jqueryui-AUTHORS.txt rename to inst/rmd/h/jqueryui/AUTHORS.txt index 2e124d3d49..0ee3fb31eb 100644 --- a/inst/rmd/h/jqueryui-AUTHORS.txt +++ b/inst/rmd/h/jqueryui/AUTHORS.txt @@ -255,7 +255,7 @@ Gan Eng Chin Gabriel Schulhof Alexander Schmitz Vilhjálmur Skúlason -Siebrand Mazeland +Siebrand Mazeland Mohsen Ekhtiari Pere Orga Jasper de Groot @@ -312,4 +312,61 @@ Mani Mishra Hannah Methvin Leonardo Balter Benjamin Albert -Michał Gołębiowski +Michał Gołębiowski-Owczarek +Alyosha Pushak +Fahad Ahmad +Matt Brundage +Francesc Baeta +Piotr Baran +Mukul Hase +Konstantin Dinev +Rand Scullard +Dan Strohl +Maksim Ryzhikov +Amine HADDAD +Amanpreet Singh +Alexey Balchunas +Peter Kehl +Peter Dave Hello +Johannes Schäfer +Ville Skyttä +Ryan Oriecuia +Sergei Ratnikov +milk54 +Evelyn Masso +Robin +Simon Asika +Kevin Cupp +Jeremy Mickelson +Kyle Rosenberg +Petri Partio +pallxk +Luke Brookhart +claudi +Eirik Sletteberg +Albert Johansson +A. Wells +Robert Brignull +Horus68 +Maksymenkov Eugene +OskarNS +Gez Quinn +jigar gala +Florian Wegscheider +Fatér Zsolt +Szabolcs Szabolcsi-Toth +Jérémy Munsch +Hrvoje Novosel +Paul Capron +Micah Miller +sakshi87 <53863764+sakshi87@users.noreply.github.com> +Mikolaj Wolicki +Patrick McKay +c-lambert <58025159+c-lambert@users.noreply.github.com> +Josep Sanz +Ben Mullins +Christian Oliff +dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> +Adam Lidén Hällgren +James Hinderks +Denny Septian Panggabean <97607754+ddevsr@users.noreply.github.com> diff --git a/inst/rmd/h/jqueryui/LICENSE.txt b/inst/rmd/h/jqueryui/LICENSE.txt new file mode 100644 index 0000000000..4819e54213 --- /dev/null +++ b/inst/rmd/h/jqueryui/LICENSE.txt @@ -0,0 +1,43 @@ +Copyright jQuery Foundation and other contributors, https://jquery.org/ + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/jquery/jquery-ui + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code contained within the demos directory. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +All files located in the node_modules and external directories are +externally maintained libraries used by this software which have their +own licenses; we recommend you read them, as their terms may differ from +the terms above. diff --git a/inst/rmd/h/jqueryui/README b/inst/rmd/h/jqueryui/README deleted file mode 100644 index 9961a1162f..0000000000 --- a/inst/rmd/h/jqueryui/README +++ /dev/null @@ -1,8 +0,0 @@ -This a jQuery UI custom build, downloaded from: -http://jqueryui.com/download/#!version=1.11.4&components=1111111111110111111111111111111111111 - -It includes all components except the datepicker, because it conflicts with -bootstrap-datepicker that is packaged with Shiny. - -The copy of jQuery that is bundled with the download, under external/, is not -included because Shiny already has its own copy of jQuery. diff --git a/inst/rmd/h/jqueryui/images/ui-icons_444444_256x240.png b/inst/rmd/h/jqueryui/images/ui-icons_444444_256x240.png index a802263b58..56d546beb3 100644 Binary files a/inst/rmd/h/jqueryui/images/ui-icons_444444_256x240.png and b/inst/rmd/h/jqueryui/images/ui-icons_444444_256x240.png differ diff --git a/inst/rmd/h/jqueryui/images/ui-icons_555555_256x240.png b/inst/rmd/h/jqueryui/images/ui-icons_555555_256x240.png index 7009bf752f..607e4362a6 100644 Binary files a/inst/rmd/h/jqueryui/images/ui-icons_555555_256x240.png and b/inst/rmd/h/jqueryui/images/ui-icons_555555_256x240.png differ diff --git a/inst/rmd/h/jqueryui/images/ui-icons_777620_256x240.png b/inst/rmd/h/jqueryui/images/ui-icons_777620_256x240.png index e0a1fdfdc0..b0482f8695 100644 Binary files a/inst/rmd/h/jqueryui/images/ui-icons_777620_256x240.png and b/inst/rmd/h/jqueryui/images/ui-icons_777620_256x240.png differ diff --git a/inst/rmd/h/jqueryui/images/ui-icons_777777_256x240.png b/inst/rmd/h/jqueryui/images/ui-icons_777777_256x240.png index 8e26ee4fd8..96c5d2222f 100644 Binary files a/inst/rmd/h/jqueryui/images/ui-icons_777777_256x240.png and b/inst/rmd/h/jqueryui/images/ui-icons_777777_256x240.png differ diff --git a/inst/rmd/h/jqueryui/images/ui-icons_cc0000_256x240.png b/inst/rmd/h/jqueryui/images/ui-icons_cc0000_256x240.png index 28154300a6..1f96135a16 100644 Binary files a/inst/rmd/h/jqueryui/images/ui-icons_cc0000_256x240.png and b/inst/rmd/h/jqueryui/images/ui-icons_cc0000_256x240.png differ diff --git a/inst/rmd/h/jqueryui/images/ui-icons_ffffff_256x240.png b/inst/rmd/h/jqueryui/images/ui-icons_ffffff_256x240.png index 4d66f596e5..d5cdbf43ca 100644 Binary files a/inst/rmd/h/jqueryui/images/ui-icons_ffffff_256x240.png and b/inst/rmd/h/jqueryui/images/ui-icons_ffffff_256x240.png differ diff --git a/inst/rmd/h/jqueryui/index.html b/inst/rmd/h/jqueryui/index.html index 7f4a59a929..9fdd811ba4 100644 --- a/inst/rmd/h/jqueryui/index.html +++ b/inst/rmd/h/jqueryui/index.html @@ -6,7 +6,7 @@ " ).appendTo( body ); - } + _processPanels: function() { + var prevHeaders = this.headers, + prevPanels = this.panels; - if(o.opacity) { // opacity option - if (this.helper.css("opacity")) { - this._storedOpacity = this.helper.css("opacity"); - } - this.helper.css("opacity", o.opacity); + if ( typeof this.options.header === "function" ) { + this.headers = this.options.header( this.element ); + } else { + this.headers = this.element.find( this.options.header ); } + this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed", + "ui-state-default" ); - if(o.zIndex) { // zIndex option - if (this.helper.css("zIndex")) { - this._storedZIndex = this.helper.css("zIndex"); - } - this.helper.css("zIndex", o.zIndex); - } + this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide(); + this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" ); - //Prepare scrolling - if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") { - this.overflowOffset = this.scrollParent.offset(); + // Avoid memory leaks (#10056) + if ( prevPanels ) { + this._off( prevHeaders.not( this.headers ) ); + this._off( prevPanels.not( this.panels ) ); } + }, - //Call callbacks - this._trigger("start", event, this._uiHash()); - - //Recache the helper size - if(!this._preserveHelperProportions) { - this._cacheHelperProportions(); - } + _refresh: function() { + var maxHeight, + options = this.options, + heightStyle = options.heightStyle, + parent = this.element.parent(); + this.active = this._findActive( options.active ); + this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" ) + ._removeClass( this.active, "ui-accordion-header-collapsed" ); + this._addClass( this.active.next(), "ui-accordion-content-active" ); + this.active.next().show(); - //Post "activate" events to possible containers - if( !noActivation ) { - for ( i = this.containers.length - 1; i >= 0; i-- ) { - this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); - } - } + this.headers + .attr( "role", "tab" ) + .each( function() { + var header = $( this ), + headerId = header.uniqueId().attr( "id" ), + panel = header.next(), + panelId = panel.uniqueId().attr( "id" ); + header.attr( "aria-controls", panelId ); + panel.attr( "aria-labelledby", headerId ); + } ) + .next() + .attr( "role", "tabpanel" ); - //Prepare possible droppables - if($.ui.ddmanager) { - $.ui.ddmanager.current = this; - } + this.headers + .not( this.active ) + .attr( { + "aria-selected": "false", + "aria-expanded": "false", + tabIndex: -1 + } ) + .next() + .attr( { + "aria-hidden": "true" + } ) + .hide(); - if ($.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); + // Make sure at least one header is in the tab order + if ( !this.active.length ) { + this.headers.eq( 0 ).attr( "tabIndex", 0 ); + } else { + this.active.attr( { + "aria-selected": "true", + "aria-expanded": "true", + tabIndex: 0 + } ) + .next() + .attr( { + "aria-hidden": "false" + } ); } - this.dragging = true; + this._createIcons(); - this.helper.addClass("ui-sortable-helper"); - this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position - return true; + this._setupEvents( options.event ); - }, + if ( heightStyle === "fill" ) { + maxHeight = parent.height(); + this.element.siblings( ":visible" ).each( function() { + var elem = $( this ), + position = elem.css( "position" ); - _mouseDrag: function(event) { - var i, item, itemElement, intersection, - o = this.options, - scrolled = false; + if ( position === "absolute" || position === "fixed" ) { + return; + } + maxHeight -= elem.outerHeight( true ); + } ); - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); + this.headers.each( function() { + maxHeight -= $( this ).outerHeight( true ); + } ); - if (!this.lastPositionAbs) { - this.lastPositionAbs = this.positionAbs; + this.headers.next() + .each( function() { + $( this ).height( Math.max( 0, maxHeight - + $( this ).innerHeight() + $( this ).height() ) ); + } ) + .css( "overflow", "auto" ); + } else if ( heightStyle === "auto" ) { + maxHeight = 0; + this.headers.next() + .each( function() { + var isVisible = $( this ).is( ":visible" ); + if ( !isVisible ) { + $( this ).show(); + } + maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); + if ( !isVisible ) { + $( this ).hide(); + } + } ) + .height( maxHeight ); } + }, - //Do scrolling - if(this.options.scroll) { - if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") { - - if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; - } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) { - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; - } - - if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; - } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) { - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; - } + _activate: function( index ) { + var active = this._findActive( index )[ 0 ]; - } else { + // Trying to activate the already active panel + if ( active === this.active[ 0 ] ) { + return; + } - if(event.pageY - this.document.scrollTop() < o.scrollSensitivity) { - scrolled = this.document.scrollTop(this.document.scrollTop() - o.scrollSpeed); - } else if(this.window.height() - (event.pageY - this.document.scrollTop()) < o.scrollSensitivity) { - scrolled = this.document.scrollTop(this.document.scrollTop() + o.scrollSpeed); - } + // Trying to collapse, simulate a click on the currently active header + active = active || this.active[ 0 ]; - if(event.pageX - this.document.scrollLeft() < o.scrollSensitivity) { - scrolled = this.document.scrollLeft(this.document.scrollLeft() - o.scrollSpeed); - } else if(this.window.width() - (event.pageX - this.document.scrollLeft()) < o.scrollSensitivity) { - scrolled = this.document.scrollLeft(this.document.scrollLeft() + o.scrollSpeed); - } + this._eventHandler( { + target: active, + currentTarget: active, + preventDefault: $.noop + } ); + }, - } + _findActive: function( selector ) { + return typeof selector === "number" ? this.headers.eq( selector ) : $(); + }, - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } + _setupEvents: function( event ) { + var events = { + keydown: "_keydown" + }; + if ( event ) { + $.each( event.split( " " ), function( index, eventName ) { + events[ eventName ] = "_eventHandler"; + } ); } - //Regenerate the absolute position used for position checks - this.positionAbs = this._convertPositionTo("absolute"); + this._off( this.headers.add( this.headers.next() ) ); + this._on( this.headers, events ); + this._on( this.headers.next(), { keydown: "_panelKeyDown" } ); + this._hoverable( this.headers ); + this._focusable( this.headers ); + }, - //Set the helper position - if(!this.options.axis || this.options.axis !== "y") { - this.helper[0].style.left = this.position.left+"px"; - } - if(!this.options.axis || this.options.axis !== "x") { - this.helper[0].style.top = this.position.top+"px"; - } + _eventHandler: function( event ) { + var activeChildren, clickedChildren, + options = this.options, + active = this.active, + clicked = $( event.currentTarget ), + clickedIsActive = clicked[ 0 ] === active[ 0 ], + collapsing = clickedIsActive && options.collapsible, + toShow = collapsing ? $() : clicked.next(), + toHide = active.next(), + eventData = { + oldHeader: active, + oldPanel: toHide, + newHeader: collapsing ? $() : clicked, + newPanel: toShow + }; - //Rearrange - for (i = this.items.length - 1; i >= 0; i--) { + event.preventDefault(); - //Cache variables and intersection, continue if no intersection - item = this.items[i]; - itemElement = item.item[0]; - intersection = this._intersectsWithPointer(item); - if (!intersection) { - continue; - } + if ( - // Only put the placeholder inside the current Container, skip all - // items from other containers. This works because when moving - // an item from one container to another the - // currentContainer is switched before the placeholder is moved. - // - // Without this, moving items in "sub-sortables" can cause - // the placeholder to jitter between the outer and inner container. - if (item.instance !== this.currentContainer) { - continue; - } + // click on active header, but not collapsible + ( clickedIsActive && !options.collapsible ) || - // cannot intersect with itself - // no useless actions that have been done before - // no action if the item moved is the parent of the item checked - if (itemElement !== this.currentItem[0] && - this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && - !$.contains(this.placeholder[0], itemElement) && - (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) - ) { + // allow canceling activation + ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { + return; + } - this.direction = intersection === 1 ? "down" : "up"; + options.active = collapsing ? false : this.headers.index( clicked ); - if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { - this._rearrange(event, item); - } else { - break; - } + // When the call to ._toggle() comes after the class changes + // it causes a very odd bug in IE 8 (see #6720) + this.active = clickedIsActive ? $() : clicked; + this._toggle( eventData ); - this._trigger("change", event, this._uiHash()); - break; - } + // Switch classes + // corner classes on the previously active header stay after the animation + this._removeClass( active, "ui-accordion-header-active", "ui-state-active" ); + if ( options.icons ) { + activeChildren = active.children( ".ui-accordion-header-icon" ); + this._removeClass( activeChildren, null, options.icons.activeHeader ) + ._addClass( activeChildren, null, options.icons.header ); } - //Post events to containers - this._contactContainers(event); + if ( !clickedIsActive ) { + this._removeClass( clicked, "ui-accordion-header-collapsed" ) + ._addClass( clicked, "ui-accordion-header-active", "ui-state-active" ); + if ( options.icons ) { + clickedChildren = clicked.children( ".ui-accordion-header-icon" ); + this._removeClass( clickedChildren, null, options.icons.header ) + ._addClass( clickedChildren, null, options.icons.activeHeader ); + } - //Interconnect with droppables - if($.ui.ddmanager) { - $.ui.ddmanager.drag(this, event); + this._addClass( clicked.next(), "ui-accordion-content-active" ); } - - //Call callbacks - this._trigger("sort", event, this._uiHash()); - - this.lastPositionAbs = this.positionAbs; - return false; - }, - _mouseStop: function(event, noPropagation) { + _toggle: function( data ) { + var toShow = data.newPanel, + toHide = this.prevShow.length ? this.prevShow : data.oldPanel; - if(!event) { - return; - } + // Handle activating a panel during the animation for another activation + this.prevShow.add( this.prevHide ).stop( true, true ); + this.prevShow = toShow; + this.prevHide = toHide; - //If we are using droppables, inform the manager about the drop - if ($.ui.ddmanager && !this.options.dropBehaviour) { - $.ui.ddmanager.drop(this, event); + if ( this.options.animate ) { + this._animate( toShow, toHide, data ); + } else { + toHide.hide(); + toShow.show(); + this._toggleComplete( data ); } - if(this.options.revert) { - var that = this, - cur = this.placeholder.offset(), - axis = this.options.axis, - animation = {}; + toHide.attr( { + "aria-hidden": "true" + } ); + toHide.prev().attr( { + "aria-selected": "false", + "aria-expanded": "false" + } ); - if ( !axis || axis === "x" ) { - animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollLeft); - } - if ( !axis || axis === "y" ) { - animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollTop); - } - this.reverting = true; - $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() { - that._clear(event); - }); - } else { - this._clear(event, noPropagation); + // if we're switching panels, remove the old header from the tab order + // if we're opening from collapsed state, remove the previous header from the tab order + // if we're collapsing, then keep the collapsing header in the tab order + if ( toShow.length && toHide.length ) { + toHide.prev().attr( { + "tabIndex": -1, + "aria-expanded": "false" + } ); + } else if ( toShow.length ) { + this.headers.filter( function() { + return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0; + } ) + .attr( "tabIndex", -1 ); } - return false; - + toShow + .attr( "aria-hidden", "false" ) + .prev() + .attr( { + "aria-selected": "true", + "aria-expanded": "true", + tabIndex: 0 + } ); }, - cancel: function() { - - if(this.dragging) { - - this._mouseUp({ target: null }); + _animate: function( toShow, toHide, data ) { + var total, easing, duration, + that = this, + adjust = 0, + boxSizing = toShow.css( "box-sizing" ), + down = toShow.length && + ( !toHide.length || ( toShow.index() < toHide.index() ) ), + animate = this.options.animate || {}, + options = down && animate.down || animate, + complete = function() { + that._toggleComplete( data ); + }; - if(this.options.helper === "original") { - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } + if ( typeof options === "number" ) { + duration = options; + } + if ( typeof options === "string" ) { + easing = options; + } - //Post deactivating events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - this.containers[i]._trigger("deactivate", null, this._uiHash(this)); - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", null, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } + // fall back from options to animation in case of partial down settings + easing = easing || options.easing || animate.easing; + duration = duration || options.duration || animate.duration; + if ( !toHide.length ) { + return toShow.animate( this.showProps, duration, easing, complete ); + } + if ( !toShow.length ) { + return toHide.animate( this.hideProps, duration, easing, complete ); } - if (this.placeholder) { - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - if(this.placeholder[0].parentNode) { - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - } - if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) { - this.helper.remove(); + total = toShow.show().outerHeight(); + toHide.animate( this.hideProps, { + duration: duration, + easing: easing, + step: function( now, fx ) { + fx.now = Math.round( now ); } - - $.extend(this, { - helper: null, - dragging: false, - reverting: false, - _noFinalSort: null - }); - - if(this.domPosition.prev) { - $(this.domPosition.prev).after(this.currentItem); - } else { - $(this.domPosition.parent).prepend(this.currentItem); - } - } - - return this; - + } ); + toShow + .hide() + .animate( this.showProps, { + duration: duration, + easing: easing, + complete: complete, + step: function( now, fx ) { + fx.now = Math.round( now ); + if ( fx.prop !== "height" ) { + if ( boxSizing === "content-box" ) { + adjust += fx.now; + } + } else if ( that.options.heightStyle !== "content" ) { + fx.now = Math.round( total - toHide.outerHeight() - adjust ); + adjust = 0; + } + } + } ); }, - serialize: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected), - str = []; - o = o || {}; + _toggleComplete: function( data ) { + var toHide = data.oldPanel, + prev = toHide.prev(); - $(items).each(function() { - var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/)); - if (res) { - str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2])); - } - }); + this._removeClass( toHide, "ui-accordion-content-active" ); + this._removeClass( prev, "ui-accordion-header-active" ) + ._addClass( prev, "ui-accordion-header-collapsed" ); - if(!str.length && o.key) { - str.push(o.key + "="); + // Work around for rendering bug in IE (#5421) + if ( toHide.length ) { + toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className; } + this._trigger( "activate", null, data ); + } +} ); - return str.join("&"); - - }, - - toArray: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected), - ret = []; - - o = o || {}; - items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); }); - return ret; - }, +var safeActiveElement = $.ui.safeActiveElement = function( document ) { + var activeElement; - /* Be careful with the following core functions */ - _intersectsWith: function(item) { + // Support: IE 9 only + // IE9 throws an "Unspecified error" accessing document.activeElement from an