ids theme: shrink overflowing slide headings onto one line (right reserve, level1 exempt)
Change-Id: I2279b0f3b3a1ae11cb39764b41fd8dccc76c0ce0
diff --git a/inst/rmarkdown/templates/revealjs_presentation/resources/default.html b/inst/rmarkdown/templates/revealjs_presentation/resources/default.html
index 4bb6834..e65dd40 100644
--- a/inst/rmarkdown/templates/revealjs_presentation/resources/default.html
+++ b/inst/rmarkdown/templates/revealjs_presentation/resources/default.html
@@ -745,6 +745,78 @@
$if(theme-ids)$
<script>
+ // IDS theme: long slide headings should shrink onto one line instead of
+ // wrapping (and pushing the orange bar taller or overflowing the slide).
+ // Slide content is laid out in fixed slide coordinates and only ever scaled
+ // by a transform, so overflow is independent of the window size and one fit
+ // pass holds everywhere. The Fira web fonts swap in asynchronously and can
+ // change text widths after reveal's initial layout, so refit when fonts and
+ // the document have finished loading too.
+ (function () {
+ var MIN_FACTOR = 0.55, // never shrink a heading below 55% of its CD size
+ RIGHT_RESERVE = 0.05; // keep fitted titles this fraction of the slide
+ // height off the right edge (and out of the logo)
+
+ function fitHeading(h) {
+ if (h.dataset.fitDone) return; // layout px don't change, fit once
+ if (!h.dataset.origFontSize) {
+ h.dataset.origFontSize = parseFloat(getComputedStyle(h).fontSize);
+ }
+ var orig = parseFloat(h.dataset.origFontSize);
+ // Slides beyond viewDistance are laid out lazily and have no overflow
+ // to measure yet (clientWidth 0); retry them once they enter layout.
+ if (!h.clientWidth) return;
+
+ var reveal = document.querySelector('.reveal');
+ var slideH = reveal && parseFloat(getComputedStyle(reveal).getPropertyValue('--slide-height')) || 720;
+ var scale = Reveal.getScale() || 1;
+ h.style.whiteSpace = 'nowrap';
+ // scrollWidth is useless here (clamped to the box width and blind to a
+ // right reserve), so measure the text itself: the range rect is in
+ // viewport coordinates, unscale into slide coordinates.
+ var range = document.createRange();
+ range.selectNodeContents(h);
+ var textW = range.getBoundingClientRect().width / scale;
+ var padLeft = parseFloat(getComputedStyle(h).paddingLeft) || 0;
+ var avail = h.clientWidth - padLeft - slideH * RIGHT_RESERVE;
+ if (textW > avail + 1) {
+ // text width is linear in font-size (letter-spacing included), so a
+ // single step fits exactly -- no iterative forced layouts
+ var size = Math.max(orig * (avail / textW) * 0.995, orig * MIN_FACTOR);
+ if (size < orig) h.style.fontSize = size + 'px';
+ }
+ h.style.whiteSpace = '';
+ h.dataset.fitDone = '1';
+ }
+
+ function fitSlideHeadings() {
+ // level1 section-divider slides deliberately stage their lone title
+ // large and centered; those may keep wrapping onto several lines.
+ document.querySelectorAll(
+ '.reveal .slides section:not(.title-frame):not(.level1) > h1:first-child, ' +
+ '.reveal .slides section:not(.title-frame) > h2:first-child, ' +
+ '.reveal .slides section:not(.title-frame) > h2:first-child + h3'
+ ).forEach(fitHeading);
+ }
+
+ function refitAll() { // fonts swapped in: widths changed, fit again
+ document.querySelectorAll('[data-fit-done]').forEach(function (h) {
+ if (h.dataset.origFontSize) h.style.fontSize = h.dataset.origFontSize + 'px';
+ delete h.dataset.fitDone;
+ });
+ fitSlideHeadings();
+ }
+
+ Reveal.on('ready', fitSlideHeadings);
+ Reveal.on('slidechanged', function () { requestAnimationFrame(fitSlideHeadings); });
+ window.addEventListener('load', fitSlideHeadings);
+ if (document.fonts && document.fonts.ready) document.fonts.ready.then(refitAll);
+ })();
+</script>
+$endif$
+
+$if(theme-ids)$
+<script>
// IDS theme: in the bibliography, "Authors (Year):" should form a bold first
// line, followed by a line break. Which part of an entry citeproc wraps in
// spans/links depends on the entry type, so a CSS "break before first child