Skip to content

Commit

Permalink
htmlDependencies are properly loaded with dynamic tabs
Browse files Browse the repository at this point in the history
  • Loading branch information
jcheng5 authored and bborgesr committed Aug 4, 2017
1 parent dde7b14 commit 91dbb0e
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 14 deletions.
47 changes: 44 additions & 3 deletions inst/www/shared/shiny.js

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

2 changes: 1 addition & 1 deletion inst/www/shared/shiny.js.map

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions inst/www/shared/shiny.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion inst/www/shared/shiny.min.js.map

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions man/insertTab.Rd

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

47 changes: 44 additions & 3 deletions srcjs/shinyapp.js
Original file line number Diff line number Diff line change
Expand Up @@ -812,10 +812,51 @@ var ShinyApp = function() {
$tabset.prepend($liTag);
}
}
$tabContent.append($divTag);

exports.renderContent($liTag[0], $liTag.html());
exports.renderContent($divTag[0], $divTag.html());
exports.renderContent($liTag[0], {html: $liTag.html(), deps: message.liTag.deps});
// jcheng 2017-07-28: This next part might look a little insane versus the
// more obvious `$tabContent.append($divTag);`, but there's a method to the
// madness.
//
// 1) We need to load the dependencies, and this needs to happen before
// any scripts in $divTag get a chance to run.
// 2) The scripts in $divTag need to run only once.
// 3) The contents of $divTag need to be sent through renderContent so that
// singletons may be registered and/or obeyed, and so that inputs/outputs
// may be bound.
//
// Add to these constraints these facts:
//
// A) The (non-jQuery) DOM manipulation functions don't cause scripts to
// run, but the jQuery functions all do.
// B) renderContent must be called on an element that's attached to the
// document.
// C) $divTag may be of length > 1 (e.g. navbarMenu). I also noticed text
// elements consisting of just "\n" being included in the nodeset of
// $divTag.
// D) renderContent has a bug where only position "replace" (the default)
// uses the jQuery functions, so other positions like "beforeend" will
// prevent child script tags from running.
//
// In theory the same problem exists for $liTag but since that content is
// much less likely to include arbitrary scripts, we're skipping it.
//
// This code could be nicer if we didn't use renderContent, but rather the
// lower-level functions that renderContent uses. Like if we pre-process
// the value of message.divTag.html for singletons, we could do that, then
// render dependencies, then do $tabContent.append($divTag).
exports.renderContent($tabContent[0], {html: "", deps: message.divTag.deps}, "beforeend");
$divTag.get().forEach(el => {
// Must not use jQuery for appending el to the doc, we don't want any
// scripts to run (since they will run when renderContent takes a crack).
$tabContent[0].appendChild(el);
// If `el` itself is a script tag, this approach won't work (the script
// won't be run), since we're only sending innerHTML through renderContent
// and not the whole tag. That's fine in this case because we control the
// R code that generates this HTML, and we know that the element is not
// a script tag.
exports.renderContent(el, el.innerHTML || el.textContent);
});

if (message.select) {
$liTag.find("a").tab("show");
Expand Down

0 comments on commit 91dbb0e

Please sign in to comment.