rstudio / htmltools

Tools for HTML generation and output
https://rstudio.github.io/htmltools/
215 stars 69 forks source link

Implement post render hooks; add hooks to tagList() #267

Open cpsievert opened 3 years ago

cpsievert commented 3 years ago

(I'm not 100% sure this is an avenue we want to pursue, but it does seem like a decent way to solve shiny::bootstrapLib()'s static rendering issues -- see https://github.com/rstudio/shiny/pull/3402 for motivation)

This main point of this PR is to add a .postRenderHook -- the primary motivation for which is to provide a way to clean-up side-effects that may happen in .renderHook. It also adds the ability to attach hooks to tagList() (this will allow us to fully deprecate tagFunction() since we can now stop using it in shiny::bootstrapLib()). Here's an example:

foo <- tags$body(
  class = "foo",
  .renderHook = function(x) {
    if (isTRUE(getOption("bar"))) tagQuery(x)$addClass("bar")$allTags() else x
  }
)

bar <- tagList(
  .renderHook = function(x) {
    options("bar" = TRUE)
    x
  },
  .postRenderHook = function() {
    options("bar" = NULL)
  }
)

foo
#> <body class="foo"></body>
tagList(bar, foo)
#> <body class="foo bar"></body>
cpsievert commented 3 years ago

@wch with 71ac6f9, .postRenderHook is now scheduling itself correctly now, but unfortunately I don’t see a way for .postRenderHook to modify its input with a single pass through the tree -- do you think that'll be an issue and/or see a way to do that?

wch commented 3 years ago

We'll need some good unit tests to make sure the pre and post hooks are executed properly.