oficina / slides Public

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

Plain git — no account needed to clone.

Download

Download this file

1// changes.mjs sorts what a transaction touched into what the editor
2// has to do about it: text on a slide flows through y-prosemirror,
3// structure on a slide means the stage re-fetches it, and a change to
4// the slide list means the strip re-syncs. Driven with a real Y.Doc
5// and real observeDeep events, because the walk from an event's target
6// up to its slide is the whole of the module.
7import test from 'node:test'
8import assert from 'node:assert/strict'
9import * as Y from 'yjs'
10import { applyOps } from './ops.mjs'
11import { classify } from './changes.mjs'
12import { blockFragment } from './stage.mjs'
13
14function deck () {
15 const doc = new Y.Doc({ guid: 'changes-test' })
16 doc.clientID = 3
17 applyOps(doc, [
18 { op: 'add_slide', id: 's1', layout: 'flow' },
19 { op: 'add_block', slide: 's1', id: 'b1', type: 'text', region: 'body', markdown: 'one' },
20 { op: 'add_slide', id: 's2', layout: 'flow' },
21 { op: 'add_block', slide: 's2', id: 'b2', type: 'heading', region: 'heading', markdown: 'two' }
22 ], 'setup')
23 const slides = doc.getArray('slides')
24 let last = null
25 slides.observeDeep(events => { last = classify(events, slides) })
26 return { doc, take: () => last }
27}
28
29test('typing into a block is a text change on its slide only', () => {
30 const { doc, take } = deck()
31 const f = blockFragment(doc, 's1', 'b1')
32 doc.transact(() => { f.get(0).get(0).insert(0, 'x') }, 'typing')
33 assert.deepEqual(take(), { text: ['s1'], structure: [], order: false })
34})
35
36test('a block\'s props changing is structure on its slide', () => {
37 const { doc, take } = deck()
38 applyOps(doc, [{ op: 'set_block', slide: 's2', id: 'b2', props: { level: 2 } }], 'ops')
39 assert.deepEqual(take(), { text: [], structure: ['s2'], order: false })
40})
41
42test('adding, moving or removing a block is structure on its slide', () => {
43 const { doc, take } = deck()
44 applyOps(doc, [{ op: 'add_block', slide: 's1', id: 'b3', type: 'text', region: 'body', markdown: 'three' }], 'ops')
45 assert.deepEqual(take(), { text: [], structure: ['s1'], order: false })
46 applyOps(doc, [{ op: 'remove_block', slide: 's1', id: 'b3' }], 'ops')
47 assert.deepEqual(take(), { text: [], structure: ['s1'], order: false })
48})
49
50test('the notes are text on their slide', () => {
51 const { doc, take } = deck()
52 applyOps(doc, [{ op: 'set_notes', id: 's2', markdown: 'note' }], 'ops')
53 assert.deepEqual(take(), { text: ['s2'], structure: [], order: false })
54})
55
56test('a slide added, removed or moved is an order change', () => {
57 const { doc, take } = deck()
58 applyOps(doc, [{ op: 'add_slide', id: 's3', layout: 'flow', after: 's1' }], 'ops')
59 assert.deepEqual(take(), { text: [], structure: [], order: true })
60 applyOps(doc, [{ op: 'move_slide', id: 's3', after: 's2' }], 'ops')
61 assert.deepEqual(take(), { text: [], structure: [], order: true })
62 applyOps(doc, [{ op: 'remove_slide', id: 's3' }], 'ops')
63 assert.deepEqual(take(), { text: [], structure: [], order: true })
64})
65
66test('one transaction touching several things reports each once', () => {
67 const { doc, take } = deck()
68 applyOps(doc, [
69 { op: 'set_slide', id: 's1', template: 'section' },
70 { op: 'set_block', slide: 's1', id: 'b1', props: { size: 'l' } },
71 { op: 'set_text', slide: 's2', id: 'b2', markdown: 'changed' }
72 ], 'ops')
73 assert.deepEqual(take(), { text: ['s2'], structure: ['s1'], order: false })
74})
75