oficina / slides Public

Clone
git clone https://amadan.net/oficina/slides

Plain git — no account needed to clone.

Download

Download this file

1// selection.mjs's hash: #<slide>[/<block>], read without ever throwing
2// — and its teardown, which is what keeps a resync from leaving a
3// second copy of every handler on the page's own elements.
4import test from 'node:test'
5import assert from 'node:assert/strict'
6import { parseHash, formatHash, mountSelection } from './selection.mjs'
7import { el, withDocument } from './dom-stub.mjs'
8
9test('parseHash splits the slide and the block, and survives a stray %', () => {
10 assert.deepEqual(parseHash('#slideaaaaaaa'), { slide: 'slideaaaaaaa', block: '' })
11 assert.deepEqual(parseHash('#slideaaaaaaa/blockbbbbbbb'), { slide: 'slideaaaaaaa', block: 'blockbbbbbbb' })
12 assert.deepEqual(parseHash(''), { slide: '', block: '' })
13 assert.deepEqual(parseHash('#'), { slide: '', block: '' })
14 assert.deepEqual(parseHash('#%'), { slide: '%', block: '' })
15 assert.deepEqual(parseHash('#a%2Fb'), { slide: 'a', block: 'b' })
16})
17
18// A resync mounts a second selection over the SAME stage element and
19// the same document, so the first one has to let go of both. The
20// Escape handler is the one that bites: it is on `document`, so a
21// leaked one clears a selection nobody is holding any more.
22test('destroy takes the listeners off, and a second mount leaves one of each', () => {
23 const ctx = withDocument()
24 try {
25 const stage = el('div', { 'slides-stage': '' })
26 const first = mountSelection({ stageEl: stage, getSlideId: () => 'slideaaaaaaa' })
27 assert.equal(stage.countListeners('click'), 1)
28 assert.equal(ctx.document.countListeners('keydown'), 1)
29
30 first.destroy()
31 assert.equal(stage.countListeners('click'), 0)
32 assert.equal(ctx.document.countListeners('keydown'), 0)
33
34 const second = mountSelection({ stageEl: stage, getSlideId: () => 'slideaaaaaaa' })
35 assert.equal(stage.countListeners('click'), 1, 'one click handler, not one per resync')
36 assert.equal(ctx.document.countListeners('keydown'), 1)
37 second.destroy()
38 } finally {
39 ctx.restore()
40 }
41})
42
43test('formatHash is the inverse', () => {
44 assert.equal(formatHash('s', 'b'), '#s/b')
45 assert.equal(formatHash('s', ''), '#s')
46 assert.equal(formatHash('', 'b'), '')
47})
48