htmlDependencies are properly loaded with dynamic tabs

This commit is contained in:
Joe Cheng
2017-07-28 02:14:50 -07:00
committed by Barbara Borges Ribeiro
parent dde7b144f0
commit 91dbb0e77b
6 changed files with 99 additions and 15 deletions

View File

@@ -1425,10 +1425,51 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
$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(function (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");

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -8,12 +8,12 @@
\title{Dynamically insert/remove a tabPanel}
\usage{
insertTab(inputId, tab, target, position = c("before", "after"),
select = FALSE, session = getDefaultReactiveDomain())
prependTab(inputId, tab, select = FALSE, menuName = NULL,
session = getDefaultReactiveDomain())
prependTab(inputId, tab, menuName = NULL,
session = getDefaultReactiveDomain())
appendTab(inputId, tab, menuName = NULL,
appendTab(inputId, tab, select = FALSE, menuName = NULL,
session = getDefaultReactiveDomain())
removeTab(inputId, target, session = getDefaultReactiveDomain())
@@ -35,6 +35,8 @@ an entire \code{navbarMenu} instead.}
\item{position}{Should \code{tab} be added before or after the
\code{target} tab?}
\item{select}{Should \code{tab} be selected upon being inserted?}
\item{session}{The shiny session within which to call this function.}
\item{menuName}{This argument should only be used when you want to

View File

@@ -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");