From 99b8b1639e27b2060c472f23a181079e845e2dc6 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 18 Mar 2025 17:41:18 +0100 Subject: [PATCH 1/4] revealjs, tabby - Trigger event for shiny rendering when tab change --- news/changelog-1.7.md | 4 ++ .../revealjs/plugins/support/support.js | 52 ++++++++++++------- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/news/changelog-1.7.md b/news/changelog-1.7.md index c4941e75be2..35bbcab61cb 100644 --- a/news/changelog-1.7.md +++ b/news/changelog-1.7.md @@ -53,6 +53,10 @@ All changes included in 1.7: - ([#11903](https://github.com/quarto-dev/quarto-cli/issues/11903)): `crossref` configuration like `fig-title` or `tbl-title` now correctly supports multi word values, e.g. `fig-title: 'Supplementary Figure'`. - ([#11878](https://github.com/quarto-dev/quarto-cli/issues/11878), [#12085](https://github.com/quarto-dev/quarto-cli/issues/12085)): Correctly fixup raw LaTeX table having an unexpected table env with options (e.g `\begin{table}[!ht]`) to be handled as crossref table. +## `revealjs` format + +- ([#12307](https://github.com/quarto-dev/quarto-cli/issues/12307)): Tabset in Revealjs now correctly render reactive content when `server: shiny` is used. + ### Quarto PDF engine - ([#12194](https://github.com/quarto-dev/quarto-cli/issues/12194)): More specific checks added in log parsing to automatically find missing fonts. diff --git a/src/resources/formats/revealjs/plugins/support/support.js b/src/resources/formats/revealjs/plugins/support/support.js index 73246a7899f..20192919260 100644 --- a/src/resources/formats/revealjs/plugins/support/support.js +++ b/src/resources/formats/revealjs/plugins/support/support.js @@ -281,36 +281,49 @@ window.QuartoSupport = function () { } } + // dispatch for htmlwidgets + // they use slideenter event to trigger resize + const fireSlideEnter = () => { + const event = window.document.createEvent("Event"); + event.initEvent("slideenter", true, true); + window.document.dispatchEvent(event); + }; + + // dispatch for shiny + // they use BS shown and hidden events to trigger rendering + const distpatchShinyEvents = (previous, current) => { + if (window.jQuery) { + if (previous) { + window.jQuery(previous).trigger("hidden"); + } + if (current) { + window.jQuery(current).trigger("shown"); + } + } + }; + function handleSlideChanges(deck) { - // dispatch for htmlwidgets - const fireSlideEnter = () => { - const event = window.document.createEvent("Event"); - event.initEvent("slideenter", true, true); - window.document.dispatchEvent(event); - }; const fireSlideChanged = (previousSlide, currentSlide) => { fireSlideEnter(); - - // dispatch for shiny - if (window.jQuery) { - if (previousSlide) { - window.jQuery(previousSlide).trigger("hidden"); - } - if (currentSlide) { - window.jQuery(currentSlide).trigger("shown"); - } - } + distpatchShinyEvents(previousSlide, currentSlide); }; - // fire slideEnter for tabby tab activations (for htmlwidget resize behavior) - document.addEventListener("tabby", fireSlideEnter, false); - deck.on("slidechanged", function (event) { fireSlideChanged(event.previousSlide, event.currentSlide); }); } + function handleTabbyChanges() { + const fireTabChanged = (previousTab, currentTab) => { + fireSlideEnter() + distpatchShinyEvents(previousTab, currentTab); + }; + document.addEventListener("tabby", function(event) { + fireTabChanged(event.detail.previousTab, event.detail.tab); + }, false); + } + function workaroundMermaidDistance(deck) { if (window.document.querySelector("pre.mermaid-js")) { const slideCount = deck.getTotalSlides(); @@ -390,6 +403,7 @@ window.QuartoSupport = function () { addFooter(deck); addChalkboardButtons(deck); handleTabbyClicks(); + handleTabbyChanges(); handleSlideChanges(deck); workaroundMermaidDistance(deck); handleWhiteSpaceInColumns(deck); From 9bb900606e8235805b0e880edd73fca71e79aff5 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 18 Mar 2025 17:50:48 +0100 Subject: [PATCH 2/4] html, tabby - also trigger event for html document when bootstrap is not used --- src/resources/formats/html/quarto.js | 30 ++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/resources/formats/html/quarto.js b/src/resources/formats/html/quarto.js index a71a420fce5..ee807684be1 100644 --- a/src/resources/formats/html/quarto.js +++ b/src/resources/formats/html/quarto.js @@ -66,19 +66,41 @@ window.document.addEventListener("DOMContentLoaded", function (_event) { } }; - // fire slideEnter for bootstrap tab activations (for htmlwidget resize behavior) - function fireSlideEnter(e) { + // dispatch for htmlwidgets + // they use slideenter event to trigger resize + function fireSlideEnter() { const event = window.document.createEvent("Event"); event.initEvent("slideenter", true, true); window.document.dispatchEvent(event); } + const tabs = window.document.querySelectorAll('a[data-bs-toggle="tab"]'); tabs.forEach((tab) => { tab.addEventListener("shown.bs.tab", fireSlideEnter); }); - // fire slideEnter for tabby tab activations (for htmlwidget resize behavior) - document.addEventListener("tabby", fireSlideEnter, false); + // dispatch for shiny + // they use BS shown and hidden events to trigger rendering + function distpatchShinyEvents(previous, current) { + if (window.jQuery) { + if (previous) { + window.jQuery(previous).trigger("hidden"); + } + if (current) { + window.jQuery(current).trigger("shown"); + } + } + } + + // tabby.js listener: Trigger event for htmlwidget and shiny + document.addEventListener( + "tabby", + function (event) { + fireSlideEnter(); + distpatchShinyEvents(event.detail.previousTab, event.detail.tab); + }, + false + ); // Track scrolling and mark TOC links as active // get table of contents and sidebar (bail if we don't have at least one) From e6c4efd8806b02d0d976d5b07a30e05ab7c77713 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Fri, 21 Mar 2025 16:32:57 +0100 Subject: [PATCH 3/4] changelog - Fix is also HTML --- news/changelog-1.7.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/news/changelog-1.7.md b/news/changelog-1.7.md index 35bbcab61cb..b8e56fd8108 100644 --- a/news/changelog-1.7.md +++ b/news/changelog-1.7.md @@ -46,6 +46,7 @@ All changes included in 1.7: - ([#12277](https://github.com/quarto-dev/quarto-cli/pull/12277)): Provide light and dark plot and table renderings with `renderings: [light,dark]` - ([#11860](https://github.com/quarto-dev/quarto-cli/issues/11860)): ES6 modules that import other local JS modules in documents with `embed-resources: true` are now correctly embedded. - ([#1325](https://github.com/quarto-dev/quarto-cli/issues/1325)): Dark Mode pages should not flash light on reload. (Nor should Light Mode pages flash dark.) +- ([#12307](https://github.com/quarto-dev/quarto-cli/issues/12307)): Tabsets using `tabby.js` in non-boostrap html (`theme: pandoc`, `theme: none` or `minimal: true`) now correctly render reactive content when `server: shiny` is used. ## `pdf` format @@ -55,7 +56,7 @@ All changes included in 1.7: ## `revealjs` format -- ([#12307](https://github.com/quarto-dev/quarto-cli/issues/12307)): Tabset in Revealjs now correctly render reactive content when `server: shiny` is used. +- ([#12307](https://github.com/quarto-dev/quarto-cli/issues/12307)): Tabsets using `tabby.js` in Revealjs now correctly render reactive content when `server: shiny` is used. ### Quarto PDF engine From c6c7a3a0caaa129dab3159e993aa1ba6a32e38ee Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Fri, 21 Mar 2025 17:29:54 +0100 Subject: [PATCH 4/4] test - start storing test file requiring `quarto serve` Like `server: shiny` example --- .../playwright/serve/shiny-r/tabby-html.qmd | 44 +++++++++++++++++++ .../playwright/serve/shiny-r/tabby-reveal.qmd | 44 +++++++++++++++++++ tests/integration/playwright-tests.test.ts | 2 +- 3 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 tests/docs/playwright/serve/shiny-r/tabby-html.qmd create mode 100644 tests/docs/playwright/serve/shiny-r/tabby-reveal.qmd diff --git a/tests/docs/playwright/serve/shiny-r/tabby-html.qmd b/tests/docs/playwright/serve/shiny-r/tabby-html.qmd new file mode 100644 index 00000000000..6f488ff504d --- /dev/null +++ b/tests/docs/playwright/serve/shiny-r/tabby-html.qmd @@ -0,0 +1,44 @@ +--- +title: "Title" +format: html +server: shiny +_quarto: + playwright-test: serve/shiny-r/shiny-tabby-html.spec.ts +--- + +```{r} +#| context: server +output$text1 <- renderText({ + "hi, it's tab 1" +}) +output$text2 <- renderText({ + "hi, it's tab 2" +}) +output$text3 <- renderText({ + "hi, it's tab 3" +}) +``` + +## Slide + +::: {.panel-tabset} + +### tab1 + +```{r} +textOutput("text1") +``` + +### tab2 + +```{r} +textOutput("text2") +``` + +### tab3 + +```{r} +textOutput("text3") +``` + +::: \ No newline at end of file diff --git a/tests/docs/playwright/serve/shiny-r/tabby-reveal.qmd b/tests/docs/playwright/serve/shiny-r/tabby-reveal.qmd new file mode 100644 index 00000000000..4cee4de9a1c --- /dev/null +++ b/tests/docs/playwright/serve/shiny-r/tabby-reveal.qmd @@ -0,0 +1,44 @@ +--- +title: "Title" +format: revealjs +server: shiny +_quarto: + playwright-test: serve/shiny-r/shiny-tabby-reveal.spec.ts +--- + +```{r} +#| context: server +output$text1 <- renderText({ + "hi, it's tab 1" +}) +output$text2 <- renderText({ + "hi, it's tab 2" +}) +output$text3 <- renderText({ + "hi, it's tab 3" +}) +``` + +## Slide + +::: {.panel-tabset} + +### tab1 + +```{r} +textOutput("text1") +``` + +### tab2 + +```{r} +textOutput("text2") +``` + +### tab3 + +```{r} +textOutput("text3") +``` + +::: \ No newline at end of file diff --git a/tests/integration/playwright-tests.test.ts b/tests/integration/playwright-tests.test.ts index 8cba2e0f369..3b857b23f29 100644 --- a/tests/integration/playwright-tests.test.ts +++ b/tests/integration/playwright-tests.test.ts @@ -24,7 +24,7 @@ async function fullInit() { const globOutput = Deno.args.length ? expandGlobSync(Deno.args[0]) : expandGlobSync( - "docs/playwright/**/*.qmd", + "docs/playwright/!(serve|shiny)/**/*.qmd", ); setInitializer(fullInit);