‘Twas brillig

So, decided to hack my own slideshow script, to dynamically turn (some of) these WP posts into slideshows…

(Published code on GitLab, even tho it’s kindda idiosyncratic? It’s called Slithy, obviously.)

Back to lecturing? Maybe. Twenty plus years ago, when I taught/lectured for a few years, we used mechanical/optical “transparencies” projection in class. Nu, prehistory. More recently, I used Google Slides to keep it simple, and portable. But today…

Alternatives

  1. Google Slides: cleaner than some (most fussing with styling can be avoided), but still no separation of concerns (ie, semantic content, so that styling is decoupled, uniform/consistent); portable (browser, responsive? NB: requires online); “social” (already); exportable (OpenDocument Presentation, PDF…)
  2. Reveal.js (~3.7MiB, 6KLOC not counting plugins — bloatware?): nested (“vertical”) slides (but only one level?), keyboard shortcuts menu, thumbnails overview, progress indicator, “fragments” (incremental slides), transition styles, iframe background, syntax highlighting (with highlight.js), URLs (eg, /#2/3/; History API), speaker notes in popup (separate browser window — Socket.IO based, shows notes, timer, preview of next slide), PDF export, API, plugins, MathJax… But, markup seems non-standard, verticals are weirdly nested <section>s?
  3. Bespoke.js (~50KiB, but key features in plugins): plugins, themes, API, UMD
  4. S5… (Bookmarked lots. Maybe later.)
  5. Centralized social media — an oxymoron? Sure, but, network effect, thus SMO?
    1. slideshare.com
    2. slides.com
    3. noti.st
    4. speakerdeck.com

    Et cetera.

Standards…

  1. The nice thing about standards is that you have so many to choose from.Tanenbaum. Also, xkcd.
  2. XOXO: historical perspective. And cute name. ;o) (BTW, WP already uses [class~=xoxo] — unrelated. WTF?)
  3. S5 microformat: much too noisy, I’ll only use maybe a couple of features — and why conform if I’m writing my own script? Anyway, it’s a useful thread to start pulling.

Requirements

  1. Markup: must not break WordPress/my theme (Stencil) — keep posts rendering normally, and don’t/minimize DOM changes. And no divitis!
  2. Nesting: tree, flattened.
  3. Unique URLs: for History API.
  4. Keyboard shortcuts
  5. Nice to have?

Markup

  1. Wrapping each slide with <section> is unavoidable (or is it?), but, testing in DevTools shows this doesn’t disrupt post’s layout — no CSS changes necessary. ;o)
  2. Can be done dynamically, in the browser. Not a trivial one-liner, pro’ly, but, “luckily”, since WP seems to force wrap text nodes (and comments!) in <p>s, all first level (.entry-content>*) nodes are ELEMENT_NODEs — much nicer to handle (since most jQuery operations don’t support text and comment nodes).
  3. Essentially, wrap each <h2> heading, and following siblings up to (.nextUntil()?) the next, or EOF, in a <section class="slide">. And move heading’s attributes to it.
  4. Did I say not a trivial one-liner?! Nu:
    $ '.entry-content>h2'
    .each (i,e)->
    	$ e
    	.nextUntil 'h2' # Following siblings.
    	.addBack() # Include self.
    	.wrapAll '<section>'
    

On demand

  1. Don’t want to mess about with the theme (WP is dead!). Or plugins. Loading a script to dynamically patch the DOM is easy enough: added this at the bottom of single.php, right before calling get_footer():
    // Inject my slideshow hacks, and *modern* jQuery as dependency.
    wp_deregister_script('jquery'); // Just to be sure?
    wp_enqueue_script('jquery','https://code.jquery.com/jquery-3.4.1.slim.min.js',array(),'3.4.1',true);
    wp_enqueue_script('slideshow',get_template_directory_uri().'/js/slideshow.js',array('jquery'),'2.1',true);
    

    (Didn’t even update entire theme, just uploaded files with scp, or SFTP with Thunar.)

  2. Even tho won’t interfere with regular posts, I’d rather only hack the DOM when necessary: given I’d tag slideshow posts anyway, and WP already inserts CSS classes for taxonomies, this becomes super easy:
    unless ($ '.post.tag-slides').length then return

Nesting

  1. I like deep trees (outlines), but they don’t render well as WP posts, so I flatten them.
  2. Structure/flow can be overlaid conveniently enough (especially using WPsuck now) with HTML attributes… and source ordering.
  3. Outline trees have equivalent (isomorphic in a sense?) binary trees; source order implicitly means sequence, so I’d only need to explicitly markup nesting. To facilitate moving slides around, while editing, I’ll go with adding [data-parent="foo"] to every (nested under #foo) slide.
  4. Hmm, [id]s. Nu.

Keyboard shortcuts

  1. I won’t animate transitions. Other scripts went with a horizontal mental model/metaphor, a strip of slides going left to right. Mine’s tree structured, and needs four keys to navigate: (1) next (or down, DFS — depth first search), (2) previous, (3) skip children, going to next sibling, and (4) up to parent.
  2. I’ll map these similar to how a file manager’s tree view does — to keyboard arrows right (also space, page down), up (and page up), down, and left, respectively. Nah, makes no sense, can’t remember these. Right/left for next/prev and up/down for, nu, up/skip, then.
  3. Also, map home and end to first and last slide.
  4. keyCode, key, or which? Effing mess. Comments, instead?
  5. Browser already handles keys for going back/forward in history.

Nice to have?

  1. Might want corresponding visual controls, à la Reveal.js.
  2. Handle URL fragments and hyperlinks to [id]s inside slides, too?
  3. Swipe?
  4. Hide/show controls and progress? On hover?
  5. Stylesheet for print.
  6. PHP: avoid loading script and everything altogether, if no slides.

Develop locally

  1. Firefox will load scripts referenced from local (file:///) documents! (Don’t need Python’s -m http.server, nor npm i http-server. ;o) So, temporarily adding these to the end of an HTML file (WPsuck!):
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script>$('body').addClass('post tag-slides entry-content').prepend('<h1 class="entry-title">Slithy</h1>')</script>
    <script src="./Code/dist/slithy.js"></script>
    <link href="./Code/dist/slithy.css" rel="stylesheet">
    

    Then, simply:

    $ sensible-browser ../Slithy.html
  2. Pro’ly should’ve done this with GreaseMonkey (et al) instead?
  3. coffee --watch didn’t work for me… over SFTP/gvfs mount? There are tons of alternatives…
  4. $ stylus --out dist --compress slithy.styl

Toggle

# Button to start the show.
$ '<button title="Slideshow" accesskey="s">📽</button>'
.insertAfter $ 'h1.entry-title'
.click ->
	$ 'body'
	.toggleClass 'slideshow'

Show just one

  1. Essentially:
    .slideshow .slide // Only apply when in slideshow mode.
    	display none // Show just one — .current.
    	&.current
    		display block
    		position fixed
    		top 0
    		bottom 0
    		left 0
    		right 0
    		overflow auto // fixed doesn't scroll.
    		background white // Mask everything else.
    
  2. Alternatively, use CSS Scroll Snap? Nu, another research project.

URLs

  1. Slides must all have IDs: because bookmarks (of individual slides, as URL fragments, obviously).
  2. Also, tho History API doesn’t require URL changes, reloading won’t preserve position without them.
  3. So, if slides aren’t explicitly ID’ed (for internal hyperlinks), then generate dynamically: based on headings, so they’re quasi constant; abbreviated; unless identical headings. (Code’s a bit dense. Nu.)

Hyper navigation

  1. Bookmarks: page might’ve been loaded with fragment (hash) in URL already:
    $ '<button title="Slideshow" accesskey="s">📽</button>'
    .click (ev)->
    	if ($ 'body.slideshow').length # Is view now in slideshow mode?
    		# Show slide: indicated in URL, otherwise first.
    		h=location.hash
    		unless h or ($ '.current').length then slide 0
    		else slide h
    
  2. History API? Assigning location.hash doesn’t reload the page, and seems to push a new history entry — and trigger popstate. (hashchange didn’t work?)

Et cetera.

And… It works. In like 120 lines of code.



Comments are closed.