| 1 | // fixtures/changes.mjs — what a transaction on the slides root means |
| 2 | // for the editor. Three kinds, and each has one consumer: |
| 3 | // |
| 4 | // text a text or notes fragment on a slide changed. Nothing to |
| 5 | // redraw: y-prosemirror already did, in every bound view. |
| 6 | // The strip re-fetches that slide's thumbnail. |
| 7 | // structure a slide's map, a block, its props, region, box or z |
| 8 | // changed. The stage re-fetches the section when it is the |
| 9 | // current slide; the strip re-fetches the thumbnail. |
| 10 | // order the slide list itself changed: a slide added, removed or |
| 11 | // moved. The strip re-syncs its items. |
| 12 | // |
| 13 | // The classification is the walk from an event's target up to the |
| 14 | // slide map whose parent is the slides array: pass through an Xml type |
| 15 | // on the way and it was text, otherwise structure; start AT the array |
| 16 | // and it was the order. One more case since the deck's order became |
| 17 | // data: a slide's own `order` key (ydoc.mjs, "reading order") is the |
| 18 | // deck's order, and move_slide writes it rather than moving array |
| 19 | // entries, so a reorder arrives as a key change on every slide map and |
| 20 | // not as an event on the array at all. Pure over Yjs types, driven in |
| 21 | // changes.test.mjs with real observeDeep events. |
| 22 | import * as Y from 'yjs' |
| 23 | import { getString } from './ydoc.mjs' |
| 24 | |
| 25 | /** {text: [slideId], structure: [slideId], order: bool} for one transaction's deep events. */ |
| 26 | export function classify (events, slides) { |
| 27 | const text = new Set() |
| 28 | const structure = new Set() |
| 29 | let order = false |
| 30 | for (const e of events) { |
| 31 | let node = e.target |
| 32 | if (node === slides) { |
| 33 | order = true |
| 34 | continue |
| 35 | } |
| 36 | let isText = false |
| 37 | while (node && node.parent !== slides) { |
| 38 | if (node instanceof Y.XmlFragment || node instanceof Y.XmlText) isText = true |
| 39 | node = node.parent |
| 40 | } |
| 41 | if (!node) continue |
| 42 | const id = getString(node, 'id') |
| 43 | if (!id) continue |
| 44 | if (isText) { text.add(id); continue } |
| 45 | // The event landed on the slide map itself. Its `order` key is the |
| 46 | // deck's order; a block's `order` key is not, and reaches here as |
| 47 | // an event further down, so keys is null for it. |
| 48 | const keys = node === e.target ? e.keysChanged : null |
| 49 | if (keys && keys.has('order')) { |
| 50 | order = true |
| 51 | // A renumbering that touched nothing else has not changed what |
| 52 | // the slide looks like, so the strip re-syncs and the stage is |
| 53 | // left alone. |
| 54 | if (keys.size === 1) continue |
| 55 | } |
| 56 | structure.add(id) |
| 57 | } |
| 58 | return { text: [...text], structure: [...structure], order } |
| 59 | } |
| 60 | |