Skip to content

Commit 8b6e053

Browse files
committed
Merge remote-tracking branch 'upstream/master' into master-revdep
* 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
2 parents 311ded3 + 62a1695 commit 8b6e053

File tree

12 files changed

+190
-68
lines changed

12 files changed

+190
-68
lines changed

DESCRIPTION

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Package: htmlwidgets
22
Type: Package
33
Title: HTML Widgets for R
4-
Version: 1.4.0.9000
4+
Version: 1.5.1.9002
55
Authors@R: c(
66
person("Ramnath", "Vaidyanathan", role = c("aut", "cph")),
77
person("Yihui", "Xie", role = c("aut")),
@@ -25,4 +25,4 @@ Suggests:
2525
Enhances: shiny (>= 1.1)
2626
URL: https://github.com/ramnathv/htmlwidgets
2727
BugReports: https://github.com/ramnathv/htmlwidgets/issues
28-
RoxygenNote: 6.1.1
28+
RoxygenNote: 7.1.1

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ S3method(as.tags,htmlwidget)
44
S3method(print,htmlwidget)
55
S3method(print,suppress_viewer)
66
export(JS)
7+
export(JSEvals)
78
export(appendContent)
89
export(createWidget)
910
export(getDependency)

R/htmlwidgets.R

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,8 @@ createWidget <- function(name,
358358
#' function.
359359
#' @param reportSize Should the widget's container size be reported in the
360360
#' shiny session's client data?
361+
#' @param reportTheme Should the widget's container styles (e.g., colors and fonts)
362+
#' be reported in the shiny session's client data?
361363
#' @param expr An expression that generates an HTML widget (or a
362364
#' \href{https://rstudio.github.io/promises/}{promise} of an HTML widget).
363365
#' @param env The environment in which to evaluate \code{expr}.
@@ -386,13 +388,27 @@ createWidget <- function(name,
386388
#'
387389
#' @export
388390
shinyWidgetOutput <- function(outputId, name, width, height, package = name,
389-
inline = FALSE, reportSize = FALSE) {
391+
inline = FALSE, reportSize = FALSE, reportTheme = FALSE) {
390392

391393
checkShinyVersion()
394+
395+
# Theme reporting requires this shiny feature
396+
# https://github.com/rstudio/shiny/pull/2740/files
397+
if (reportTheme &&
398+
nzchar(system.file(package = "shiny")) &&
399+
packageVersion("shiny") < "1.4.0.9003") {
400+
message("`reportTheme = TRUE` requires shiny v.1.4.0.9003 or higher. Consider upgrading shiny.")
401+
}
402+
392403
# generate html
393404
html <- htmltools::tagList(
394-
widget_html(name, package, id = outputId,
395-
class = paste0(name, " html-widget html-widget-output", if (reportSize) " shiny-report-size"),
405+
widget_html(
406+
name, package, id = outputId,
407+
class = paste0(
408+
name, " html-widget html-widget-output",
409+
if (reportSize) " shiny-report-size",
410+
if (reportTheme) " shiny-report-theme"
411+
),
396412
style = sprintf("width:%s; height:%s; %s",
397413
htmltools::validateCssUnit(width),
398414
htmltools::validateCssUnit(height),

R/utils.R

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -128,19 +128,29 @@ JS <- function(...) {
128128
structure(x, class = unique(c("JS_EVAL", oldClass(x))))
129129
}
130130

131-
# Creates a list of keys whose values need to be evaluated on the client-side.
132-
#
133-
# It works by transforming \code{list(foo = list(1, list(bar =
134-
# I('function(){}')), 2))} to \code{list("foo.2.bar")}. Later on the JS side, we
135-
# will split foo.2.bar to ['foo', '2', 'bar'] and evaluate the JSON object
136-
# member. Note '2' (character) should have been 2 (integer) but it does not seem
137-
# to matter in JS: x[2] is the same as x['2'] when all child members of x are
138-
# unnamed, and ('2' in x) will be true even if x is an array without names. This
139-
# is a little hackish.
140-
#
141-
# @param list a list in which the elements that should be evaluated as
142-
# JavaScript are to be identified
143-
# @author Yihui Xie
131+
#' Creates a list of keys whose values need to be evaluated on the client-side
132+
#'
133+
#' It works by transforming \code{list(foo = list(1, list(bar =
134+
#' I('function(){}')), 2))} to \code{list("foo.2.bar")}. Later on the JS side,
135+
#' the \code{window.HTMLWidgets.evaluateStringMember} function is called with
136+
#' the JSON object and the "foo.2.bar" string, which is split to \code{['foo',
137+
#' '2', 'bar']}, and the string at that location is replaced \emph{in-situ} with
138+
#' the results of evaluating it. Note '2' (character) should have been 2
139+
#' (integer) but it does not seem to matter in JS: x[2] is the same as x['2']
140+
#' when all child members of x are unnamed, and ('2' in x) will be true even if
141+
#' x is an array without names. This is a little hackish.
142+
#'
143+
#' This function is intended mostly for internal use. There's generally no need
144+
#' for widget authors or users to call it, as it's called automatically on the
145+
#' widget instance data during rendering. It's exported in case other packages
146+
#' want to add support for \code{\link{JS}} in contexts outside of widget
147+
#' payloads.
148+
#'
149+
#' @param list a list in which the elements that should be evaluated as
150+
#' JavaScript are to be identified
151+
#' @author Yihui Xie
152+
#' @keywords internal
153+
#' @export
144154
JSEvals <- function(list) {
145155
# the `%||% list()` part is necessary as of R 3.4.0 (April 2017) -- if `evals`
146156
# is NULL then `I(evals)` results in a warning in R 3.4.0. This is circumvented

inst/NEWS

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
htmlwidgets 1.5.1.9000
2+
-------------------------------------------------------
3+
4+
* Fixed an issue with passing named function declarations to `JS()` and `onRender()` (introduced by v1.4). (#356)
5+
6+
* 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)
7+
8+
* Export the `JSEvals` function, allowing other packages to support `JS()` in non-widget contexts.
9+
10+
htmlwidgets 1.5.1
11+
-------------------------------------------------------
12+
13+
* 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)
14+
115
htmlwidgets 1.5
216
-----------------------------------------------------------------------
317

inst/www/htmlwidgets.js

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -249,13 +249,13 @@
249249
function tryEval(code) {
250250
var result = null;
251251
try {
252-
result = eval(code);
252+
result = eval("(" + code + ")");
253253
} catch(error) {
254254
if (!error instanceof SyntaxError) {
255255
throw error;
256256
}
257257
try {
258-
result = eval("(" + code + ")");
258+
result = eval(code);
259259
} catch(e) {
260260
if (e instanceof SyntaxError) {
261261
throw error;
@@ -659,44 +659,56 @@
659659
invokePostRenderHandlers();
660660
}
661661

662-
// Wait until after the document has loaded to render the widgets.
663-
if (shinyMode && window.jQuery) {
664-
/*
665-
/ Shiny 1.4.0 bumps jQuery from 1.x to 3.x, which means jQuery's
666-
/ on-ready handler (i.e., $(fn)) is now asyncronous (i.e., it now
667-
/ really means $(setTimeout(fn)). https://jquery.com/upgrade-guide/3.0/#breaking-change-document-ready-handlers-are-now-asynchronous
668-
/
669-
/ In order to ensure the order of execution of on-ready handlers
670-
/ remains consistent with how it's been in the past, a static render
671-
/ in Shiny is now scheduled via $().
672-
/
673-
/ This is not a long term solution: it just preserves the current order
674-
/ of execution. Part of that ordering is to ensure initShiny executes
675-
/ _after_ staticRender, which is both right and wrong:
676-
/ * It's wrong because, when initShiny executes, it registers methods
677-
/ like Shiny.onInputChange that widget authors would expect to be available
678-
/ during a staticRender.
679-
/ * It's also 'right' because initShiny currently (as of v1.4.0) wants
680-
/ to execute after user code so that it can bind to any dynamically
681-
/ created elements.
682-
/
683-
/ A longer term solution might be to make changes to Shiny so that
684-
/ these methods are available before the binding takes place, and then
685-
/ the ordering would be: register methods -> static render -> bind.
686-
*/
687-
window.jQuery(function() {
662+
663+
function has_jQuery3() {
664+
if (!window.jQuery) {
665+
return false;
666+
}
667+
var $version = window.jQuery.fn.jquery;
668+
var $major_version = parseInt($version.split(".")[0]);
669+
return $major_version >= 3;
670+
}
671+
672+
/*
673+
/ Shiny 1.4 bumped jQuery from 1.x to 3.x which means jQuery's
674+
/ on-ready handler (i.e., $(fn)) is now asyncronous (i.e., it now
675+
/ really means $(setTimeout(fn)).
676+
/ https://jquery.com/upgrade-guide/3.0/#breaking-change-document-ready-handlers-are-now-asynchronous
677+
/
678+
/ Since Shiny uses $() to schedule initShiny, shiny>=1.4 calls initShiny
679+
/ one tick later than it did before, which means staticRender() is
680+
/ called renderValue() earlier than (advanced) widget authors might be expecting.
681+
/ https://github.com/rstudio/shiny/issues/2630
682+
/
683+
/ For a concrete example, leaflet has some methods (e.g., updateBounds)
684+
/ which reference Shiny methods registered in initShiny (e.g., setInputValue).
685+
/ Since leaflet is privy to this life-cycle, it knows to use setTimeout() to
686+
/ delay execution of those methods (until Shiny methods are ready)
687+
/ https://github.com/rstudio/leaflet/blob/18ec981/javascript/src/index.js#L266-L268
688+
/
689+
/ Ideally widget authors wouldn't need to use this setTimeout() hack that
690+
/ leaflet uses to call Shiny methods on a staticRender(). In the long run,
691+
/ the logic initShiny should be broken up so that method registration happens
692+
/ right away, but binding happens later.
693+
*/
694+
function maybeStaticRenderLater() {
695+
if (shinyMode && has_jQuery3()) {
696+
window.jQuery(window.HTMLWidgets.staticRender);
697+
} else {
688698
window.HTMLWidgets.staticRender();
689-
});
690-
} else if (document.addEventListener) {
699+
}
700+
}
701+
702+
if (document.addEventListener) {
691703
document.addEventListener("DOMContentLoaded", function() {
692704
document.removeEventListener("DOMContentLoaded", arguments.callee, false);
693-
window.HTMLWidgets.staticRender();
705+
maybeStaticRenderLater();
694706
}, false);
695707
} else if (document.attachEvent) {
696708
document.attachEvent("onreadystatechange", function() {
697709
if (document.readyState === "complete") {
698710
document.detachEvent("onreadystatechange", arguments.callee);
699-
window.HTMLWidgets.staticRender();
711+
maybeStaticRenderLater();
700712
}
701713
});
702714
}

man/JSEvals.Rd

Lines changed: 34 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/createWidget.Rd

Lines changed: 11 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/htmlwidgets-shiny.Rd

Lines changed: 13 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/saveWidget.Rd

Lines changed: 9 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)