diff --git a/.vscode/settings.json b/.vscode/settings.json index 6c5d51ddb39..985c5a00039 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -15,5 +15,6 @@ "deno.enable": true, "deno.lint": true, "deno.unstable": true, - "deno.importMap": "./src/import_map.json" + "deno.importMap": "./src/import_map.json", + "deno.disablePaths": ["tests/integration/playwright/"] } diff --git a/news/changelog-1.6.md b/news/changelog-1.6.md index d440be7c29c..f89cec91e30 100644 --- a/news/changelog-1.6.md +++ b/news/changelog-1.6.md @@ -34,6 +34,7 @@ All changes included in 1.6: - Update to Reveal JS 5.1.0. - Support for a [Jump To Slide](https://revealjs.com/jump-to-slide/) menu to quickly navigate between slides. Set `jump-to-slide: false` to opt out. + - Support for new [Scroll View](https://revealjs.com/scroll-view/) mode with configuration through new `scroll-view` revealjs's format configuration key. A new menu tool has been added to toggle scroll view mode on and off, associated with `R` key by default. - Prevent empty SASS built css file to be included in header. - Remove wrong `sourceMappingUrl` entry in SASS built css. - ([#7715](https://github.com/quarto-dev/quarto-cli/issues/7715)): Revealjs don't support anymore special Pandoc syntax making BulletList in Blockquotes become incremental list. This was confusing and unexpected behavior. Supported syntax for incremental list is documented at . diff --git a/src/format/reveal/constants.ts b/src/format/reveal/constants.ts index 84833a06fce..6fd3caebc16 100644 --- a/src/format/reveal/constants.ts +++ b/src/format/reveal/constants.ts @@ -24,3 +24,10 @@ export const kAutoAnimateUnmatched = "autoAnimateUnmatched"; export const kAutoStretch = "auto-stretch"; export const kCodeBlockHeight = "code-block-height"; export const kJumpToSlide = "jumpToSlide"; +// scroll view configurations - https://revealjs.com/scroll-view/ +export const kScrollView = "scroll-view"; +export const kView = "view"; +export const kScrollProgress = "scrollProgress"; +export const kScrollSnap = "scrollSnap"; +export const kScrollActivationWidth = "scrollActivationWidth"; +export const kScrollLayout = "scrollLayout"; diff --git a/src/format/reveal/format-reveal-plugin.ts b/src/format/reveal/format-reveal-plugin.ts index 5e2e7452778..6c34be92931 100644 --- a/src/format/reveal/format-reveal-plugin.ts +++ b/src/format/reveal/format-reveal-plugin.ts @@ -420,6 +420,11 @@ function revealMenuTools(format: Format) { key: "e", handler: "togglePdfExport", }, + { + title: "Scroll View Mode", + key: "r", + handler: "toggleScrollView", + }, ]; if (format.metadata[kRevealChalkboard]) { tools.push( diff --git a/src/format/reveal/format-reveal.ts b/src/format/reveal/format-reveal.ts index 596ed529f76..acc212ae964 100644 --- a/src/format/reveal/format-reveal.ts +++ b/src/format/reveal/format-reveal.ts @@ -62,8 +62,14 @@ import { kPreviewLinksAuto, kRevealJsConfig, kScrollable, + kScrollActivationWidth, + kScrollLayout, + kScrollProgress, + kScrollSnap, + kScrollView, kSlideFooter, kSlideLogo, + kView, } from "./constants.ts"; import { revealMetadataFilter } from "./metadata.ts"; import { ProjectContext } from "../../project/types.ts"; @@ -78,6 +84,36 @@ export function revealResolveFormat(format: Format) { if (format.metadata["navigationMode"] === "vertical") { format.metadata["navigationMode"] = "default"; } + + // normalize scroll-view to map to revealjs configuration + const scrollView = format.metadata[kScrollView]; + if (typeof scrollView === "boolean" && scrollView) { + // if scroll-view is true then set view to scroll by default + // using all default option + format.metadata[kView] = "scroll"; + } else if (typeof scrollView === "object") { + // if scroll-view is an object then map to revealjs configuration individually + const scrollViewRecord = scrollView as Record; + // Only activate scroll by default when ask explicitly + if (scrollViewRecord["activate"] === true) { + format.metadata[kView] = "scroll"; + } + if (scrollViewRecord["progress"] !== undefined) { + format.metadata[kScrollProgress] = scrollViewRecord["progress"]; + } + if (scrollViewRecord["snap"] !== undefined) { + format.metadata[kScrollSnap] = scrollViewRecord["snap"]; + } + if (scrollViewRecord["layout"] !== undefined) { + format.metadata[kScrollLayout] = scrollViewRecord["layout"]; + } + if (scrollViewRecord["activation-width"] !== undefined) { + format.metadata[kScrollActivationWidth] = + scrollViewRecord["activation-width"]; + } + } + // remove scroll-view from metadata + delete format.metadata[kScrollView]; } export function revealjsFormat() { @@ -153,6 +189,24 @@ export function revealjsFormat() { format.metadata[kPdfMaxPagesPerSlide]; } + // pass scroll view settings as they are not yet in revealjs template + if (format.metadata[kView]) { + extraConfig[kView] = format.metadata[kView]; + } + if (format.metadata[kScrollProgress] !== undefined) { + extraConfig[kScrollProgress] = format.metadata[kScrollProgress]; + } + if (format.metadata[kScrollSnap] !== undefined) { + extraConfig[kScrollSnap] = format.metadata[kScrollSnap]; + } + if (format.metadata[kScrollLayout] !== undefined) { + extraConfig[kScrollLayout] = format.metadata[kScrollLayout]; + } + if (format.metadata[kScrollActivationWidth] !== undefined) { + extraConfig[kScrollActivationWidth] = + format.metadata[kScrollActivationWidth]; + } + // get theme info (including text highlighing mode) const theme = await revealTheme( format, diff --git a/src/format/reveal/metadata.ts b/src/format/reveal/metadata.ts index 9db6dbacd47..3a019f69a47 100644 --- a/src/format/reveal/metadata.ts +++ b/src/format/reveal/metadata.ts @@ -13,6 +13,11 @@ import { kJumpToSlide, kPdfMaxPagesPerSlide, kPdfSeparateFragments, + kScrollActivationWidth, + kScrollLayout, + kScrollProgress, + kScrollSnap, + kView, } from "./constants.ts"; export function optionsToKebab(options: string[]) { @@ -120,6 +125,11 @@ const kRevealOptions = [ kPdfSeparateFragments, "pdfPageHeightOffset", kJumpToSlide, + kView, + kScrollProgress, + kScrollSnap, + kScrollLayout, + kScrollActivationWidth, ]; const kRevealKebabOptions = optionsToKebab(kRevealOptions); diff --git a/src/resources/editor/tools/vs-code.mjs b/src/resources/editor/tools/vs-code.mjs index 1f7fdee55b7..b020cd377aa 100644 --- a/src/resources/editor/tools/vs-code.mjs +++ b/src/resources/editor/tools/vs-code.mjs @@ -18601,6 +18601,66 @@ var require_yaml_intelligence_resources = __commonJS({ } ] } + }, + { + name: "scroll-view", + description: "Control the scroll view feature of Revealjs", + tags: { + formats: [ + "revealjs" + ] + }, + schema: { + anyOf: [ + "boolean", + { + object: { + properties: { + activate: { + boolean: { + default: true, + description: "Activate scroll view by default for the presentation. Otherwise, it is manually avalaible by adding `?view=scroll` to url." + } + }, + progress: { + anyOf: [ + "boolean", + { + enum: [ + "auto" + ] + } + ], + default: "auto", + description: "Show the scrollbar while scrolling, hide while idle (default `auto`). Set to 'true' to always show, `false` to always hide." + }, + snap: { + enum: [ + "mandatory", + "proximity", + false + ], + default: "mandatory", + description: "When scrolling, it will automatically snap to the closest slide. Only snap when close to the top of a slide using `proximity`. Disable snapping altogether by setting to `false`.\n" + }, + layout: { + enum: [ + "compact", + "full" + ], + default: "full", + description: "By default each slide will be sized to be as tall as the viewport. If you prefer a more dense layout with multiple slides visible in parallel, set to `compact`.\n" + }, + "activation-width": { + number: { + description: "Control scroll view activation width. The scroll view is automatically unable when the viewport reaches mobile widths. Set to `0` to disable automatic scroll view.\n" + } + } + } + } + } + ] + } } ], "schema/document-reveal-transitions.yml": [ @@ -23045,6 +23105,12 @@ var require_yaml_intelligence_resources = __commonJS({ "Multiplex token server (defaults to Reveal-hosted server)", "Unique presentation id provided by multiplex token server", "Secret provided by multiplex token server", + "Control the scroll view feature of Revealjs", + "Activate scroll view by default for the presentation. Otherwise, it\nis manually avalaible by adding ?view=scroll to url.", + "Show the scrollbar while scrolling, hide while idle (default\nauto). Set to \u2018true\u2019 to always show, false to\nalways hide.", + "When scrolling, it will automatically snap to the closest slide. Only\nsnap when close to the top of a slide using proximity.\nDisable snapping altogether by setting to false.", + "By default each slide will be sized to be as tall as the viewport. If\nyou prefer a more dense layout with multiple slides visible in parallel,\nset to compact.", + "Control scroll view activation width. The scroll view is\nautomatically unable when the viewport reaches mobile widths. Set to\n0 to disable automatic scroll view.", { short: "Transition style for slides", long: "Transition style for slides backgrounds. (none,\nfade, slide, convex,\nconcave, or zoom)" @@ -23855,8 +23921,7 @@ var require_yaml_intelligence_resources = __commonJS({ }, "Disambiguating year suffix in author-date styles (e.g. \u201Ca\u201D in \u201CDoe,\n1999a\u201D).", "Manuscript configuration", - "internal-schema-hack", - "Alternative text for the logo, used for accessibility." + "internal-schema-hack" ], "schema/external-schemas.yml": [ { @@ -24085,12 +24150,12 @@ var require_yaml_intelligence_resources = __commonJS({ mermaid: "%%" }, "handlers/mermaid/schema.yml": { - _internalId: 190453, + _internalId: 192356, type: "object", description: "be an object", properties: { "mermaid-format": { - _internalId: 190445, + _internalId: 192348, type: "enum", enum: [ "png", @@ -24106,7 +24171,7 @@ var require_yaml_intelligence_resources = __commonJS({ exhaustiveCompletions: true }, theme: { - _internalId: 190452, + _internalId: 192355, type: "anyOf", anyOf: [ { diff --git a/src/resources/editor/tools/yaml/web-worker.js b/src/resources/editor/tools/yaml/web-worker.js index 86fac6c2a7d..f1e51dd5ded 100644 --- a/src/resources/editor/tools/yaml/web-worker.js +++ b/src/resources/editor/tools/yaml/web-worker.js @@ -18602,6 +18602,66 @@ try { } ] } + }, + { + name: "scroll-view", + description: "Control the scroll view feature of Revealjs", + tags: { + formats: [ + "revealjs" + ] + }, + schema: { + anyOf: [ + "boolean", + { + object: { + properties: { + activate: { + boolean: { + default: true, + description: "Activate scroll view by default for the presentation. Otherwise, it is manually avalaible by adding `?view=scroll` to url." + } + }, + progress: { + anyOf: [ + "boolean", + { + enum: [ + "auto" + ] + } + ], + default: "auto", + description: "Show the scrollbar while scrolling, hide while idle (default `auto`). Set to 'true' to always show, `false` to always hide." + }, + snap: { + enum: [ + "mandatory", + "proximity", + false + ], + default: "mandatory", + description: "When scrolling, it will automatically snap to the closest slide. Only snap when close to the top of a slide using `proximity`. Disable snapping altogether by setting to `false`.\n" + }, + layout: { + enum: [ + "compact", + "full" + ], + default: "full", + description: "By default each slide will be sized to be as tall as the viewport. If you prefer a more dense layout with multiple slides visible in parallel, set to `compact`.\n" + }, + "activation-width": { + number: { + description: "Control scroll view activation width. The scroll view is automatically unable when the viewport reaches mobile widths. Set to `0` to disable automatic scroll view.\n" + } + } + } + } + } + ] + } } ], "schema/document-reveal-transitions.yml": [ @@ -23046,6 +23106,12 @@ try { "Multiplex token server (defaults to Reveal-hosted server)", "Unique presentation id provided by multiplex token server", "Secret provided by multiplex token server", + "Control the scroll view feature of Revealjs", + "Activate scroll view by default for the presentation. Otherwise, it\nis manually avalaible by adding ?view=scroll to url.", + "Show the scrollbar while scrolling, hide while idle (default\nauto). Set to \u2018true\u2019 to always show, false to\nalways hide.", + "When scrolling, it will automatically snap to the closest slide. Only\nsnap when close to the top of a slide using proximity.\nDisable snapping altogether by setting to false.", + "By default each slide will be sized to be as tall as the viewport. If\nyou prefer a more dense layout with multiple slides visible in parallel,\nset to compact.", + "Control scroll view activation width. The scroll view is\nautomatically unable when the viewport reaches mobile widths. Set to\n0 to disable automatic scroll view.", { short: "Transition style for slides", long: "Transition style for slides backgrounds. (none,\nfade, slide, convex,\nconcave, or zoom)" @@ -23856,8 +23922,7 @@ try { }, "Disambiguating year suffix in author-date styles (e.g. \u201Ca\u201D in \u201CDoe,\n1999a\u201D).", "Manuscript configuration", - "internal-schema-hack", - "Alternative text for the logo, used for accessibility." + "internal-schema-hack" ], "schema/external-schemas.yml": [ { @@ -24086,12 +24151,12 @@ try { mermaid: "%%" }, "handlers/mermaid/schema.yml": { - _internalId: 190453, + _internalId: 192356, type: "object", description: "be an object", properties: { "mermaid-format": { - _internalId: 190445, + _internalId: 192348, type: "enum", enum: [ "png", @@ -24107,7 +24172,7 @@ try { exhaustiveCompletions: true }, theme: { - _internalId: 190452, + _internalId: 192355, type: "anyOf", anyOf: [ { diff --git a/src/resources/editor/tools/yaml/yaml-intelligence-resources.json b/src/resources/editor/tools/yaml/yaml-intelligence-resources.json index c6a710059a0..6d69cf755ba 100644 --- a/src/resources/editor/tools/yaml/yaml-intelligence-resources.json +++ b/src/resources/editor/tools/yaml/yaml-intelligence-resources.json @@ -11573,6 +11573,66 @@ } ] } + }, + { + "name": "scroll-view", + "description": "Control the scroll view feature of Revealjs", + "tags": { + "formats": [ + "revealjs" + ] + }, + "schema": { + "anyOf": [ + "boolean", + { + "object": { + "properties": { + "activate": { + "boolean": { + "default": true, + "description": "Activate scroll view by default for the presentation. Otherwise, it is manually avalaible by adding `?view=scroll` to url." + } + }, + "progress": { + "anyOf": [ + "boolean", + { + "enum": [ + "auto" + ] + } + ], + "default": "auto", + "description": "Show the scrollbar while scrolling, hide while idle (default `auto`). Set to 'true' to always show, `false` to always hide." + }, + "snap": { + "enum": [ + "mandatory", + "proximity", + false + ], + "default": "mandatory", + "description": "When scrolling, it will automatically snap to the closest slide. Only snap when close to the top of a slide using `proximity`. Disable snapping altogether by setting to `false`.\n" + }, + "layout": { + "enum": [ + "compact", + "full" + ], + "default": "full", + "description": "By default each slide will be sized to be as tall as the viewport. If you prefer a more dense layout with multiple slides visible in parallel, set to `compact`.\n" + }, + "activation-width": { + "number": { + "description": "Control scroll view activation width. The scroll view is automatically unable when the viewport reaches mobile widths. Set to `0` to disable automatic scroll view.\n" + } + } + } + } + } + ] + } } ], "schema/document-reveal-transitions.yml": [ @@ -16017,6 +16077,12 @@ "Multiplex token server (defaults to Reveal-hosted server)", "Unique presentation id provided by multiplex token server", "Secret provided by multiplex token server", + "Control the scroll view feature of Revealjs", + "Activate scroll view by default for the presentation. Otherwise, it\nis manually avalaible by adding ?view=scroll to url.", + "Show the scrollbar while scrolling, hide while idle (default\nauto). Set to ‘true’ to always show, false to\nalways hide.", + "When scrolling, it will automatically snap to the closest slide. Only\nsnap when close to the top of a slide using proximity.\nDisable snapping altogether by setting to false.", + "By default each slide will be sized to be as tall as the viewport. If\nyou prefer a more dense layout with multiple slides visible in parallel,\nset to compact.", + "Control scroll view activation width. The scroll view is\nautomatically unable when the viewport reaches mobile widths. Set to\n0 to disable automatic scroll view.", { "short": "Transition style for slides", "long": "Transition style for slides backgrounds. (none,\nfade, slide, convex,\nconcave, or zoom)" @@ -16827,8 +16893,7 @@ }, "Disambiguating year suffix in author-date styles (e.g. “a” in “Doe,\n1999a”).", "Manuscript configuration", - "internal-schema-hack", - "Alternative text for the logo, used for accessibility." + "internal-schema-hack" ], "schema/external-schemas.yml": [ { @@ -17057,12 +17122,12 @@ "mermaid": "%%" }, "handlers/mermaid/schema.yml": { - "_internalId": 190453, + "_internalId": 192356, "type": "object", "description": "be an object", "properties": { "mermaid-format": { - "_internalId": 190445, + "_internalId": 192348, "type": "enum", "enum": [ "png", @@ -17078,7 +17143,7 @@ "exhaustiveCompletions": true }, "theme": { - "_internalId": 190452, + "_internalId": 192355, "type": "anyOf", "anyOf": [ { diff --git a/src/resources/formats/revealjs/plugins/menu/quarto-menu.js b/src/resources/formats/revealjs/plugins/menu/quarto-menu.js index 96740536977..f23962e3b9e 100644 --- a/src/resources/formats/revealjs/plugins/menu/quarto-menu.js +++ b/src/resources/formats/revealjs/plugins/menu/quarto-menu.js @@ -40,4 +40,7 @@ window.RevealMenuToolHandlers = { togglePdfExport: revealMenuToolHandler(function () { PdfExport.togglePdfExport(); }), + toggleScrollView: revealMenuToolHandler(function() { + Reveal.getPlugin("quarto-support").toggleScrollView(Reveal)(); + }) }; diff --git a/src/resources/formats/revealjs/plugins/support/support.js b/src/resources/formats/revealjs/plugins/support/support.js index 9d627cd8878..727cc4f632d 100644 --- a/src/resources/formats/revealjs/plugins/support/support.js +++ b/src/resources/formats/revealjs/plugins/support/support.js @@ -128,10 +128,13 @@ window.QuartoSupport = function () { // tweak slide-number element function tweakSlideNumber(deck) { deck.on("slidechanged", function (ev) { + // No slide number in scroll view + if (deck.isScrollView()) { return } const revealParent = deck.getRevealElement(); const slideNumberEl = revealParent.querySelector(".slide-number"); - const onDarkBackground = Reveal.getSlideBackground(ev.indexh, ev.indexv).classList.contains('has-dark-background'); - const onLightBackground = Reveal.getSlideBackground(ev.indexh, ev.indexv).classList.contains('has-light-background'); + const slideBackground = Reveal.getSlideBackground(ev.currentSlide); + const onDarkBackground = slideBackground.classList.contains('has-dark-background') + const onLightBackground = slideBackground.classList.contains('has-light-background') toggleBackgroundTheme(slideNumberEl, onDarkBackground, onLightBackground); }) } @@ -144,8 +147,8 @@ window.QuartoSupport = function () { // or show default unless data-footer="false" for no footer on this slide const setSlideFooter = (ev, defaultFooterDiv) => { const currentSlideFooter = ev.currentSlide.querySelector(".footer"); - const onDarkBackground = deck.getSlideBackground(ev.indexh, ev.indexv).classList.contains('has-dark-background') - const onLightBackground = deck.getSlideBackground(ev.indexh, ev.indexv).classList.contains('has-light-background') + const onDarkBackground = deck.getSlideBackground(ev.currentSlide).classList.contains('has-dark-background') + const onLightBackground = deck.getSlideBackground(ev.currentSlide).classList.contains('has-light-background') if (currentSlideFooter) { defaultFooterDiv.style.display = "none"; const slideFooter = currentSlideFooter.cloneNode(true); @@ -342,6 +345,33 @@ window.QuartoSupport = function () { } } + // FIXME: Possibly remove this wrapper when upstream trigger is fixed + // https://github.com/hakimel/reveal.js/issues/3688 + // Currently, scrollActivationWidth needs to be unset for toggle to work + function toggleScrollViewWrapper(deck) { + let oldscrollActivationWidth; + return () => { + if (deck.isScrollView() === true) { + deck.configure({scrollActivationWidth: oldscrollActivationWidth}); + deck.toggleScrollView(false); + } else if (deck.isScrollView() === false) { + oldscrollActivationWidth = deck.getConfig()['scrollActivationWidth']; + deck.configure({scrollActivationWidth: null}); + deck.toggleScrollView(true); + } + } + } + + function installScollViewKeyBindings(deck) { + var config = deck.getConfig(); + var shortcut = config.scrollViewShortcut || 'R'; + Reveal.addKeyBinding({ + keyCode: shortcut.toUpperCase().charCodeAt( 0 ), + key: shortcut.toUpperCase(), + description: 'Scroll View Mode' + }, toggleScrollViewWrapper(deck) ); + } + return { id: "quarto-support", init: function (deck) { @@ -357,8 +387,11 @@ window.QuartoSupport = function () { handleSlideChanges(deck); workaroundMermaidDistance(deck); handleWhiteSpaceInColumns(deck); + installScollViewKeyBindings(deck); // should stay last cleanEmptyAutoGeneratedContent(deck); }, + // Export for adding in menu + toggleScrollView: toggleScrollViewWrapper, }; }; diff --git a/src/resources/schema/document-reveal-tools.yml b/src/resources/schema/document-reveal-tools.yml index 48ca67d6a7e..a7d7f8195cf 100644 --- a/src/resources/schema/document-reveal-tools.yml +++ b/src/resources/schema/document-reveal-tools.yml @@ -96,3 +96,37 @@ secret: string: description: Secret provided by multiplex token server + +- name: scroll-view + description: Control the scroll view feature of Revealjs + tags: + formats: [revealjs] + schema: + anyOf: + - boolean + - object: + properties: + activate: + boolean: + default: true + description: "Activate scroll view by default for the presentation. Otherwise, it is manually avalaible by adding `?view=scroll` to url." + progress: + anyOf: + - boolean + - enum: ["auto"] + default: "auto" + description: "Show the scrollbar while scrolling, hide while idle (default `auto`). Set to 'true' to always show, `false` to always hide." + snap: + enum: ["mandatory", "proximity", false] + default: "mandatory" + description: > + When scrolling, it will automatically snap to the closest slide. Only snap when close to the top of a slide using `proximity`. Disable snapping altogether by setting to `false`. + layout: + enum: ["compact", "full"] + default: full + description: | + By default each slide will be sized to be as tall as the viewport. If you prefer a more dense layout with multiple slides visible in parallel, set to `compact`. + activation-width: + number: + description: | + Control scroll view activation width. The scroll view is automatically unable when the viewport reaches mobile widths. Set to `0` to disable automatic scroll view. diff --git a/tests/docs/playwright/revealjs/scroll-view-activate.qmd b/tests/docs/playwright/revealjs/scroll-view-activate.qmd new file mode 100644 index 00000000000..83f68133942 --- /dev/null +++ b/tests/docs/playwright/revealjs/scroll-view-activate.qmd @@ -0,0 +1,22 @@ +--- +format: + revealjs: + scroll-view: true +--- + +## Slide 1 + +Content + +## Slide 2 + +Content + +## Slide 3 + +Content + +## Slide 4 + +Content + diff --git a/tests/docs/smoke-all/revealjs/scroll-view-config.qmd b/tests/docs/smoke-all/revealjs/scroll-view-config.qmd new file mode 100644 index 00000000000..76c4089544a --- /dev/null +++ b/tests/docs/smoke-all/revealjs/scroll-view-config.qmd @@ -0,0 +1,31 @@ +--- +title: "Jump to slide" +format: + revealjs: + scroll-view: + activate: true + progress: true + snap: false + layout: compact + activation-width: 0 +_quarto: + tests: + revealjs: + ensureFileRegexMatches: + - + - '''view'': "scroll",' + - '''scrollProgress'': true,' + - '''scrollSnap'': false,' + - '''scrollLayout'': "compact",' + - '''scrollActivationWidth'': 0,' + - [] +--- + +## test + +Content + +## test + +Content + diff --git a/tests/integration/playwright/tests/revealjs.spec.ts b/tests/integration/playwright/tests/revealjs.spec.ts index 8370993bc79..c15f05cfbcf 100644 --- a/tests/integration/playwright/tests/revealjs.spec.ts +++ b/tests/integration/playwright/tests/revealjs.spec.ts @@ -1,6 +1,6 @@ -import { test, expect } from '@playwright/test'; +import { test, expect, Page } from '@playwright/test'; -test('logo and footer are correctly shown', async ({ page }) => { +test('logo and footer are correctly shown in default mode', async ({ page }) => { await page.goto('./revealjs/logo-footer.html#/slide-1'); await expect(page.locator('.reveal > .footer.footer-default')).toContainText('Footer text'); await expect(page.locator('.slide-logo')).toHaveAttribute("src", "quarto.png"); @@ -16,6 +16,58 @@ test('logo and footer are correctly shown', async ({ page }) => { await expect(page.locator('.slide-logo')).toHaveAttribute("src", "quarto.png"); }); +test('logo and footer are correctly shown in scroll mode', async ({ page }) => { + // check scroll mode too + await page.goto('revealjs/logo-footer.html?view=scroll'); + await expect(page.locator('.reveal > .footer.footer-default')).toContainText('Footer text'); + await expect(page.locator('.slide-logo')).toHaveAttribute("src", "quarto.png"); + await page.keyboard.press('ArrowRight'); // Next slide + await expect(page.locator('.reveal > .footer.footer-default')).toContainText('Footer text'); + await expect(page.locator('.slide-logo')).toHaveAttribute("src", "quarto.png"); + await page.keyboard.press('ArrowRight'); // Next slide + await expect(page.locator('.reveal > .footer')).toBeHidden(); + await expect(page.locator('.slide-logo')).toHaveAttribute("src", "quarto.png"); + await page.keyboard.press('ArrowRight'); // Next slide + await expect(page.locator('.reveal > .footer.footer-default')).toBeHidden(); + await expect(page.locator('.reveal > .footer:not(.footer-default)')).toContainText('A different footer'); + await expect(page.locator('.slide-logo')).toHaveAttribute("src", "quarto.png"); +}); + +async function expectScrollViewMode(page: Page, isActive: boolean) { + expect(await page.evaluate(() => (window as any).Reveal.isScrollView())).toBe(isActive); + if (isActive) { + await expect(page.locator('.scrollbar-playhead')).toBeVisible(); + } else { + await expect(page.locator('.scrollbar-playhead')).toBeHidden(); + } +} + +async function clickScrollViewMenuButton(page: Page) { + await page.locator('div.slide-menu-button').click(); + await page.locator('li').filter({ hasText: 'Tools' }).click(); + expect(page.locator('li').filter({ hasText: 'Scroll View Mode' })).toBeVisible(); + await page.getByRole('link', { name: 'r Scroll View Mode' }).click(); +} + +test('scroll view mode is correctly activated with menu and shortcut', async ({ page }) => { + await page.goto('revealjs/scroll-view-activate.html'); + // should be activated by default + await expectScrollViewMode(page, true); + // deactivate + await clickScrollViewMenuButton(page); + await expectScrollViewMode(page, false); + // activate + await clickScrollViewMenuButton(page); + await expectScrollViewMode(page, true); + // keyboard shortcuts works too + // -- deactivate + await page.keyboard.press('R'); + await expectScrollViewMode(page, false); + // -- activate + await page.keyboard.press('R'); + await expectScrollViewMode(page, true); +}); + test('internal id for links between slides are working', async ({ page }) => { await page.goto('./revealjs/links-id.html#/link-to-the-figure'); await page.getByRole('link', { name: 'Figure Element' }).click(); @@ -29,4 +81,4 @@ test('internal id for links between slides are working', async ({ page }) => { await page.goto('./revealjs/links-id.html#/link-to-theorem'); await page.getByRole('link', { name: 'Theorem' }).click(); await page.waitForURL(/theorem$/); -}); \ No newline at end of file +});