Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into master-revdep
Browse files Browse the repository at this point in the history
* upstream/master:
  Bump dev version
  Export JSEvals (ramnathv#381)
  Add missing roxygenize step (ramnathv#370)
  Add reportTheme arg to shinyWidgetOutput() (ramnathv#361)
  Try evaluating code with parentheses before without parentheses, closes ramnathv#356. (ramnathv#357)
  Bump version for development
  v1.5.1 release candidate (ramnathv#353)
  Add a comment; abstract out duplication in logic (ramnathv#354)
  Prevent staticRender from being called unconditionally when htmlwidgets.js is loaded after page load
  Bump version; update NEWS
  Use  to schedule staticRender() iff jQuery 3 or higher is present in shinyMode
  Bump version
  Bump version for release
  • Loading branch information
schloerke committed Sep 30, 2020
2 parents 311ded3 + 62a1695 commit 8b6e053
Show file tree
Hide file tree
Showing 12 changed files with 190 additions and 68 deletions.
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: htmlwidgets
Type: Package
Title: HTML Widgets for R
Version: 1.4.0.9000
Version: 1.5.1.9002
Authors@R: c(
person("Ramnath", "Vaidyanathan", role = c("aut", "cph")),
person("Yihui", "Xie", role = c("aut")),
Expand All @@ -25,4 +25,4 @@ Suggests:
Enhances: shiny (>= 1.1)
URL: https://github.com/ramnathv/htmlwidgets
BugReports: https://github.com/ramnathv/htmlwidgets/issues
RoxygenNote: 6.1.1
RoxygenNote: 7.1.1
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ S3method(as.tags,htmlwidget)
S3method(print,htmlwidget)
S3method(print,suppress_viewer)
export(JS)
export(JSEvals)
export(appendContent)
export(createWidget)
export(getDependency)
Expand Down
22 changes: 19 additions & 3 deletions R/htmlwidgets.R
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,8 @@ createWidget <- function(name,
#' function.
#' @param reportSize Should the widget's container size be reported in the
#' shiny session's client data?
#' @param reportTheme Should the widget's container styles (e.g., colors and fonts)
#' be reported in the shiny session's client data?
#' @param expr An expression that generates an HTML widget (or a
#' \href{https://rstudio.github.io/promises/}{promise} of an HTML widget).
#' @param env The environment in which to evaluate \code{expr}.
Expand Down Expand Up @@ -386,13 +388,27 @@ createWidget <- function(name,
#'
#' @export
shinyWidgetOutput <- function(outputId, name, width, height, package = name,
inline = FALSE, reportSize = FALSE) {
inline = FALSE, reportSize = FALSE, reportTheme = FALSE) {

checkShinyVersion()

# Theme reporting requires this shiny feature
# https://github.com/rstudio/shiny/pull/2740/files
if (reportTheme &&
nzchar(system.file(package = "shiny")) &&
packageVersion("shiny") < "1.4.0.9003") {
message("`reportTheme = TRUE` requires shiny v.1.4.0.9003 or higher. Consider upgrading shiny.")
}

# generate html
html <- htmltools::tagList(
widget_html(name, package, id = outputId,
class = paste0(name, " html-widget html-widget-output", if (reportSize) " shiny-report-size"),
widget_html(
name, package, id = outputId,
class = paste0(
name, " html-widget html-widget-output",
if (reportSize) " shiny-report-size",
if (reportTheme) " shiny-report-theme"
),
style = sprintf("width:%s; height:%s; %s",
htmltools::validateCssUnit(width),
htmltools::validateCssUnit(height),
Expand Down
36 changes: 23 additions & 13 deletions R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -128,19 +128,29 @@ JS <- function(...) {
structure(x, class = unique(c("JS_EVAL", oldClass(x))))
}

# Creates a list of keys whose values need to be evaluated on the client-side.
#
# It works by transforming \code{list(foo = list(1, list(bar =
# I('function(){}')), 2))} to \code{list("foo.2.bar")}. Later on the JS side, we
# will split foo.2.bar to ['foo', '2', 'bar'] and evaluate the JSON object
# member. Note '2' (character) should have been 2 (integer) but it does not seem
# to matter in JS: x[2] is the same as x['2'] when all child members of x are
# unnamed, and ('2' in x) will be true even if x is an array without names. This
# is a little hackish.
#
# @param list a list in which the elements that should be evaluated as
# JavaScript are to be identified
# @author Yihui Xie
#' Creates a list of keys whose values need to be evaluated on the client-side
#'
#' It works by transforming \code{list(foo = list(1, list(bar =
#' I('function(){}')), 2))} to \code{list("foo.2.bar")}. Later on the JS side,
#' the \code{window.HTMLWidgets.evaluateStringMember} function is called with
#' the JSON object and the "foo.2.bar" string, which is split to \code{['foo',
#' '2', 'bar']}, and the string at that location is replaced \emph{in-situ} with
#' the results of evaluating it. Note '2' (character) should have been 2
#' (integer) but it does not seem to matter in JS: x[2] is the same as x['2']
#' when all child members of x are unnamed, and ('2' in x) will be true even if
#' x is an array without names. This is a little hackish.
#'
#' This function is intended mostly for internal use. There's generally no need
#' for widget authors or users to call it, as it's called automatically on the
#' widget instance data during rendering. It's exported in case other packages
#' want to add support for \code{\link{JS}} in contexts outside of widget
#' payloads.
#'
#' @param list a list in which the elements that should be evaluated as
#' JavaScript are to be identified
#' @author Yihui Xie
#' @keywords internal
#' @export
JSEvals <- function(list) {
# the `%||% list()` part is necessary as of R 3.4.0 (April 2017) -- if `evals`
# is NULL then `I(evals)` results in a warning in R 3.4.0. This is circumvented
Expand Down
14 changes: 14 additions & 0 deletions inst/NEWS
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
htmlwidgets 1.5.1.9000
-------------------------------------------------------

* Fixed an issue with passing named function declarations to `JS()` and `onRender()` (introduced by v1.4). (#356)

* Added a `reportTheme` argument to `shinyWidgetOutput()`. If `TRUE`, CSS styles of the widget's output container are made available to `shiny::getCurrentOutputInfo()`, making it possible to provide 'smart' styling defaults in a `renderWidget()` context. (#361)

* Export the `JSEvals` function, allowing other packages to support `JS()` in non-widget contexts.

htmlwidgets 1.5.1
-------------------------------------------------------

* Fixed an issue with dynamically rendered widgets (i.e., using `shiny::uiOutput()` to render a widget) with any version of shiny prior to 1.4. This issue was introduced by htmlwidgets 1.5. (#351)

htmlwidgets 1.5
-----------------------------------------------------------------------

Expand Down
76 changes: 44 additions & 32 deletions inst/www/htmlwidgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,13 +249,13 @@
function tryEval(code) {
var result = null;
try {
result = eval(code);
result = eval("(" + code + ")");
} catch(error) {
if (!error instanceof SyntaxError) {
throw error;
}
try {
result = eval("(" + code + ")");
result = eval(code);
} catch(e) {
if (e instanceof SyntaxError) {
throw error;
Expand Down Expand Up @@ -659,44 +659,56 @@
invokePostRenderHandlers();
}

// Wait until after the document has loaded to render the widgets.
if (shinyMode && window.jQuery) {
/*
/ Shiny 1.4.0 bumps jQuery from 1.x to 3.x, which means jQuery's
/ on-ready handler (i.e., $(fn)) is now asyncronous (i.e., it now
/ really means $(setTimeout(fn)). https://jquery.com/upgrade-guide/3.0/#breaking-change-document-ready-handlers-are-now-asynchronous
/
/ In order to ensure the order of execution of on-ready handlers
/ remains consistent with how it's been in the past, a static render
/ in Shiny is now scheduled via $().
/
/ This is not a long term solution: it just preserves the current order
/ of execution. Part of that ordering is to ensure initShiny executes
/ _after_ staticRender, which is both right and wrong:
/ * It's wrong because, when initShiny executes, it registers methods
/ like Shiny.onInputChange that widget authors would expect to be available
/ during a staticRender.
/ * It's also 'right' because initShiny currently (as of v1.4.0) wants
/ to execute after user code so that it can bind to any dynamically
/ created elements.
/
/ A longer term solution might be to make changes to Shiny so that
/ these methods are available before the binding takes place, and then
/ the ordering would be: register methods -> static render -> bind.
*/
window.jQuery(function() {

function has_jQuery3() {
if (!window.jQuery) {
return false;
}
var $version = window.jQuery.fn.jquery;
var $major_version = parseInt($version.split(".")[0]);
return $major_version >= 3;
}

/*
/ Shiny 1.4 bumped jQuery from 1.x to 3.x which means jQuery's
/ on-ready handler (i.e., $(fn)) is now asyncronous (i.e., it now
/ really means $(setTimeout(fn)).
/ https://jquery.com/upgrade-guide/3.0/#breaking-change-document-ready-handlers-are-now-asynchronous
/
/ Since Shiny uses $() to schedule initShiny, shiny>=1.4 calls initShiny
/ one tick later than it did before, which means staticRender() is
/ called renderValue() earlier than (advanced) widget authors might be expecting.
/ https://github.com/rstudio/shiny/issues/2630
/
/ For a concrete example, leaflet has some methods (e.g., updateBounds)
/ which reference Shiny methods registered in initShiny (e.g., setInputValue).
/ Since leaflet is privy to this life-cycle, it knows to use setTimeout() to
/ delay execution of those methods (until Shiny methods are ready)
/ https://github.com/rstudio/leaflet/blob/18ec981/javascript/src/index.js#L266-L268
/
/ Ideally widget authors wouldn't need to use this setTimeout() hack that
/ leaflet uses to call Shiny methods on a staticRender(). In the long run,
/ the logic initShiny should be broken up so that method registration happens
/ right away, but binding happens later.
*/
function maybeStaticRenderLater() {
if (shinyMode && has_jQuery3()) {
window.jQuery(window.HTMLWidgets.staticRender);
} else {
window.HTMLWidgets.staticRender();
});
} else if (document.addEventListener) {
}
}

if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", function() {
document.removeEventListener("DOMContentLoaded", arguments.callee, false);
window.HTMLWidgets.staticRender();
maybeStaticRenderLater();
}, false);
} else if (document.attachEvent) {
document.attachEvent("onreadystatechange", function() {
if (document.readyState === "complete") {
document.detachEvent("onreadystatechange", arguments.callee);
window.HTMLWidgets.staticRender();
maybeStaticRenderLater();
}
});
}
Expand Down
34 changes: 34 additions & 0 deletions man/JSEvals.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 11 additions & 3 deletions man/createWidget.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 13 additions & 2 deletions man/htmlwidgets-shiny.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 9 additions & 3 deletions man/saveWidget.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 19 additions & 9 deletions man/sizingPolicy.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion vignettes/develop_intro.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,8 @@ This method is highly recommended as it ensures that you get started with the ri

```r
devtools::create("mywidget") # create package using devtools
setwd("mywidget") # navigate to package dir
htmlwidgets::scaffoldWidget("mywidget") # create widget scaffolding
devtools::document() # roxygenize, so NAMESPACE is updated
devtools::install() # install the package so we can try it
```

Expand Down

0 comments on commit 8b6e053

Please sign in to comment.