Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

* htmlwidgets hex sticker added

* Static widget resize detection now uses `ResizeObserver` instead of `window.resize`, Bootstrap tab/collapse, and ioslides event listeners. This enables widgets to detect container-level size changes (e.g., CSS-driven resizing, sidebar toggles, flexbox/grid layout changes) that were previously missed. (#496)

# htmlwidgets 1.6.4

This release reverts the change made in v1.6.3 (to no longer recurse into list-like objects when searching for JavaScript strings wrapped in `JS()`). Although that change helped prevent infinite recursion in some cases, it ultimately broke too many existing widgets that relied on the previous behavior. If you encounter infinite recursion errors ("C stack usage is too close to the limit"), the best strategy is to coerce the offending items to a character string. (#478)
Expand Down
49 changes: 16 additions & 33 deletions inst/www/htmlwidgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,16 @@
}
}

var resizeObserver = typeof ResizeObserver !== "undefined" ?
new ResizeObserver(function(entries) {
entries.forEach(function(entry) {
var resizeHandler = elementData(entry.target, "resize_handler");
if (resizeHandler) {
resizeHandler(entry);
}
});
}) : null;

// Render static widgets after the document finishes loading
// Statically render all elements that are of this widget's class
window.HTMLWidgets.staticRender = function() {
Expand Down Expand Up @@ -596,7 +606,7 @@

if (binding.resize) {
var lastSize = getSize(el);
var resizeHandler = function(e) {
var resizeHandler = function() {
var size = getSize(el);
if (size.w === 0 && size.h === 0)
return;
Expand All @@ -606,38 +616,11 @@
binding.resize(el, size.w, size.h, initResult);
};

on(window, "resize", resizeHandler);

// This is needed for cases where we're running in a Shiny
// app, but the widget itself is not a Shiny output, but
// rather a simple static widget. One example of this is
// an rmarkdown document that has runtime:shiny and widget
// that isn't in a render function. Shiny only knows to
// call resize handlers for Shiny outputs, not for static
// widgets, so we do it ourselves.
if (window.jQuery) {
window.jQuery(document).on(
"shown.htmlwidgets shown.bs.tab.htmlwidgets shown.bs.collapse.htmlwidgets",
resizeHandler
);
window.jQuery(document).on(
"hidden.htmlwidgets hidden.bs.tab.htmlwidgets hidden.bs.collapse.htmlwidgets",
resizeHandler
);
}

// This is needed for the specific case of ioslides, which
// flips slides between display:none and display:block.
// Ideally we would not have to have ioslide-specific code
// here, but rather have ioslides raise a generic event,
// but the rmarkdown package just went to CRAN so the
// window to getting that fixed may be long.
if (window.addEventListener) {
// It's OK to limit this to window.addEventListener
// browsers because ioslides itself only supports
// such browsers.
on(document, "slideenter", resizeHandler);
on(document, "slideleave", resizeHandler);
if (resizeObserver) {
elementData(el, "resize_handler", resizeHandler);
resizeObserver.observe(el);
} else {
on(window, "resize", resizeHandler);
}
}

Expand Down
Loading