remark icon indicating copy to clipboard operation
remark copied to clipboard

Hide incremental slides

Open trombonehero opened this issue 6 years ago • 12 comments

Thanks very much for remark.js: I use it extensively when preparing lecture material for courses that I teach (see, e.g., http://www.engr.mun.ca/~anderson/teaching/3891/lecture).

I like to use incremental builds in the classroom, but when I distribute PDF versions of the lecture notes (slides + presenter notes with CSS to turn key words into blank spaces for students to fill in) I don't want to show all of the incremental steps. My current workflow requires me to manually go through the PDF output from Chrome's "Print to PDF" and delete all of the intermediate pages. This is a labour-intensive, slightly error-prone process. It would be really handy if I could run remark in a mode that only showed the final version of each complete (non-incremental) slide.

trombonehero avatar Oct 23 '17 14:10 trombonehero

I've just hacked out this workaround, sharing in case it's useful to anyone else:

function hidePrintSlides(slideshow) {
  const allSlides = slideshow.getSlides();
  let lastSlide;
  let currentSlide;
  const slidesToHide = [];
  const slidesEl = document.getElementsByClassName("remark-slides-area")[0];
  const slideEls = slidesEl.children;
  for (let i = 0; i < allSlides.length; i++) {
    lastSlide = currentSlide;
    currentSlide = allSlides[i];
    if (lastSlide && (
      String(lastSlide.properties.continued) === "true"
      ||
      String(currentSlide.properties.count) === "false"
    )) {
      const slideToHideIndex = i - 1;
      slidesToHide.push(slideToHideIndex);
      slideEls[slideToHideIndex].className = slideEls[slideToHideIndex].className + ' has-continuation';
    }
  }
}

Basically call this function (passing the slideshow instance) and it'll automatically add has-continuation to slides that are followed by another slide that doesn't increment the slide number (i.e. where count is set false, or where they use a continuation --). Assumes that the option countIncrementalSlides is set to false.

Then you can add a print stylesheet to your CSS to remove the slides:

@media print {
  .has-continuation {
    display: none;
  }
}

benjie avatar Apr 22 '18 12:04 benjie

@benjie thanks for looking at it! I tried your recipe, but it didn't help in my case (the presentation is here). Do you actually have a "minimal working example" somewhere?

ulysses4ever avatar Apr 23 '18 10:04 ulysses4ever

Make sure it fires after the DOM is ready. I don't have a minimal example right now - sorry 😞

benjie avatar Apr 23 '18 16:04 benjie

Would be great to have this feature somehow built in.

For the next reader, I took a different approach and added a little R snippet to my presentation to create a copy of the file, use grep to remove all -- lines, and then create the PDF from that (and clean up), see https://zivgitlab.uni-muenster.de/d_nues01/git-digital-humanities/blob/master/git-digital-humanities.Rmd#L15

library("webshot")
system("cat presentation.Rmd | grep -v '^--$' > print.Rmd")
rmarkdown::render('print.Rmd', 'xaringan::moon_reader')
file_name <- paste0("file://", normalizePath("print.html"))
webshot(file_name, "git-digital-humanities.pdf")
system("rm -r print.Rmd print.html print_files")

nuest avatar Jun 26 '18 15:06 nuest

Looks like there might have been a change to the way the continued property is applied to slides since @benjie posted his code. In particular, it looks like continued is "false" for the first slide of each "full" slide (perhaps it used to be the last one?). This leads to changing:

String(lastSlide.properties.continued) === "true"

to

String(currentSlide.properties.continued) === "true"

Anyway, the following full example seems to work for me with this change:

<!DOCTYPE html>
<html>
  <head>
    <title>Print Full Slides</title>
    <meta charset="utf-8">
    <style>
      @import url(https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz);
      @import url(https://fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic);
      @import url(https://fonts.googleapis.com/css?family=Ubuntu+Mono:400,700,400italic);

      body { font-family: 'Droid Serif'; }
      h1, h2, h3 {
        font-family: 'Yanone Kaffeesatz';
        font-weight: normal;
      }
	  code {
        background: #e7e8e2;
        border-radius: 5px;
      }
      @media print {
          .has-continuation {
              display: none;
          }
      }
      .remark-code, .remark-inline-code { font-family: 'Ubuntu Mono'; }
    </style>
  </head>
  <body>
    <textarea id="source">

class: center, middle

# Remark Issue - Continuation

---
# Agenda
--

1. Topic 1
--


1. Topic 2
--


1. Topic 3
--


1. Topic 4
--


1. Topic 5


---
# Topic 1
--

Some text

--

More text

---
# Topic 2

Single slide text


---
# Topic 3
--

Some text

--

More text

---
# Topic 4

Single slide text

---

# Topic 5

--

Some text

--

More text

    </textarea>
    <script src="https://gnab.github.io/remark/downloads/remark-latest.min.js">
    </script>
    <script>
        // https://github.com/gnab/remark/issues/478#issuecomment-383377112
        function hidePrintSlides(slideshow) {
          const allSlides = slideshow.getSlides();
          let lastSlide;
          let currentSlide;
          const slidesToHide = [];
          const slidesEl = document.getElementsByClassName("remark-slides-area")[0];
          const slideEls = slidesEl.children;
          for (let i = 0; i < allSlides.length; i++) {
            lastSlide = currentSlide;
            currentSlide = allSlides[i];
            if (lastSlide && (
              String(currentSlide.properties.continued) === "true"
              ||
              String(currentSlide.properties.count) === "false"
            )) {
              const slideToHideIndex = i - 1;
              slidesToHide.push(slideToHideIndex);
              slideEls[slideToHideIndex].className = slideEls[slideToHideIndex].className + ' has-continuation';
            }
          }
        }
    </script>
    <script>
      remark.macros.scale = function (percentage) {
          var url = this;
          return '<img src="' + url + '" style="width: ' + percentage + '" />';
      };
      var slideshow = remark.create({
          highlightLanguage: 'python',
          highlightStyle: 'solarized-dark',
          highlightLines: false,
          countIncrementalSlides: false  // needed by hidePrintSlides()
      });
      hidePrintSlides(slideshow);
    </script>
  </body>
</html>

I haven't tested it extensively, but the only quirk I've noticed so far is that you get an extra blank page at the end of the PDF.

I hope that's useful.

DavidAntliff avatar Sep 11 '18 23:09 DavidAntliff

@DavidAntliff thanks for your instructions! Unfortunately, they don't work for me as expected. I have

Chromium
Version 69.0.3497.81 (Official Build) Built on Ubuntu , running on Ubuntu 18.04 (64-bit)

And it prints all the overlayed pages. Also, the size is wrong. Print Full Slides.pdf

ulysses4ever avatar Sep 14 '18 15:09 ulysses4ever

@ulysses4ever strange, I am only able to test on Ubuntu 16.04/Chrome 69 and Mac OSX 10.12.6/Chrome 68, but in both cases it seems to work for me.

Print.Full.Slides-DA.pdf

Only difference seems to be that on my Mac I don't get a blank page at the end.

The size is another issue and might be helped by https://github.com/gnab/remark/issues/50#issuecomment-223887379

DavidAntliff avatar Sep 15 '18 01:09 DavidAntliff

I think @DavidAntliff was correct: @benjie's original code contained a little bug.

Here is my "old-school" JS code, which also tries to inject the CSS to <head> (I also found the variables slidesToHide and lastSlide unnecessary):

(function(d) {
  var el = d.getElementsByClassName("remark-slides-area");
  if (!el) return;
  var slide, slides = slideshow.getSlides(), els = el[0].children;
  for (var i = 1; i < slides.length; i++) {
    slide = slides[i];
    if (slide.properties.continued === "true" || slide.properties.count === "false") {
      els[i - 1].className += ' has-continuation';
    }
  }
  var s = d.createElement("style");
  s.type = "text/css";
  s.innerHTML = "@media print { .has-continuation { display: none; } }";
  d.head.appendChild(s);
})(document);

Test: https://slides.yihui.name/xaringan/

yihui avatar Feb 07 '19 18:02 yihui

I used this workaround: sed '/^--$/d' original.md > no_incremental_slides.md

andreymoser avatar Dec 04 '20 15:12 andreymoser

Not sure why this is still open with two workarounds listed here. Should we close the issue?

abelards avatar Feb 08 '21 08:02 abelards

With remark.js 0.15.0, you no longer need the workarounds, because 295155567e652bfceb83f4356c556a27f52506b0 introduced a CSS class to incremental slides, so you can define CSS rules to hide these slides easily. However, the current "latest" release of remark.js is still 0.14.1 because 0.15.0 also introduced some breaking changes (6e2325d23edbe48178000285dbd8bae6ae95ea21).

yihui avatar Feb 08 '21 19:02 yihui

It would be nice to have documentation (for every corresponding release) for this particular use case: when I'm using incremental slides markup (--), how do I convert to PDF so that only the last slide in every series goes to PDF.

ulysses4ever avatar Feb 08 '21 19:02 ulysses4ever