edytor 0.0.11 → 0.1.0-next.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -197
- package/dist/block/block.svelte.d.ts +156 -69
- package/dist/block/block.svelte.js +324 -355
- package/dist/block/block.utils.d.ts +191 -24
- package/dist/block/block.utils.js +327 -460
- package/dist/block/contentRange.d.ts +4 -0
- package/dist/block/contentRange.js +20 -0
- package/dist/block/inlineBlock.svelte.d.ts +26 -19
- package/dist/block/inlineBlock.svelte.js +91 -39
- package/dist/clipboard/clipboard.d.ts +4 -0
- package/dist/clipboard/clipboard.js +4 -0
- package/dist/clipboard/createClipboardFragment.d.ts +3 -0
- package/dist/clipboard/createClipboardFragment.js +103 -0
- package/dist/clipboard/fragmentData.d.ts +6 -0
- package/dist/clipboard/fragmentData.js +74 -0
- package/dist/clipboard/htmlFlow.d.ts +22 -0
- package/dist/clipboard/htmlFlow.js +167 -0
- package/dist/clipboard/insertClipboardFragment.d.ts +18 -0
- package/dist/clipboard/insertClipboardFragment.js +48 -0
- package/dist/clipboard/serializeClipboardFragment.d.ts +7 -0
- package/dist/clipboard/serializeClipboardFragment.js +53 -0
- package/dist/clipboard/textBlocks.d.ts +23 -0
- package/dist/clipboard/textBlocks.js +103 -0
- package/dist/clipboard/types.d.ts +20 -0
- package/dist/clipboard/types.js +2 -0
- package/dist/cloudflare/DocumentRoom.d.ts +586 -0
- package/dist/cloudflare/DocumentRoom.js +1706 -0
- package/dist/cloudflare/index.d.ts +8 -0
- package/dist/cloudflare/index.js +8 -0
- package/dist/cloudflare/routeDocumentSocket.d.ts +33 -0
- package/dist/cloudflare/routeDocumentSocket.js +51 -0
- package/dist/collaboration/RemoteSelections.svelte +94 -0
- package/dist/collaboration/RemoteSelections.svelte.d.ts +7 -0
- package/dist/collaboration/awarenessSelection.d.ts +127 -0
- package/dist/collaboration/awarenessSelection.js +199 -0
- package/dist/collaboration/documentSync.d.ts +20 -0
- package/dist/collaboration/documentSync.js +13 -0
- package/dist/collaboration/index.d.ts +3 -0
- package/dist/collaboration/index.js +3 -0
- package/dist/collaboration/providers.d.ts +13 -0
- package/dist/collaboration/providers.js +21 -0
- package/dist/collaboration/remoteSelection.d.ts +21 -0
- package/dist/collaboration/remoteSelection.js +159 -0
- package/dist/components/Block.svelte +223 -15
- package/dist/components/Block.svelte.d.ts +4 -2
- package/dist/components/Content.svelte +128 -32
- package/dist/components/Content.svelte.d.ts +6 -2
- package/dist/components/Edytor.svelte +308 -110
- package/dist/components/Edytor.svelte.d.ts +64 -20
- package/dist/components/InlineBlock.svelte +38 -7
- package/dist/components/InlineBlock.svelte.d.ts +5 -2
- package/dist/components/Mark.svelte +29 -13
- package/dist/components/Mark.svelte.d.ts +4 -4
- package/dist/components/Suggestion.svelte +48 -0
- package/dist/components/Suggestion.svelte.d.ts +7 -0
- package/dist/components/SuggestionRanges.svelte +58 -0
- package/dist/components/SuggestionRanges.svelte.d.ts +7 -0
- package/dist/components/Text.svelte +107 -14
- package/dist/components/Text.svelte.d.ts +8 -1
- package/dist/constants.d.ts +0 -2
- package/dist/constants.js +0 -2
- package/dist/crdt/admission.d.ts +141 -0
- package/dist/crdt/admission.js +147 -0
- package/dist/crdt/anchors.d.ts +47 -0
- package/dist/crdt/anchors.js +42 -0
- package/dist/crdt/attribution/attribution.d.ts +169 -0
- package/dist/crdt/attribution/attribution.js +136 -0
- package/dist/crdt/attribution/block.d.ts +200 -0
- package/dist/crdt/attribution/block.js +327 -0
- package/dist/crdt/attribution/index.d.ts +9 -0
- package/dist/crdt/attribution/index.js +9 -0
- package/dist/crdt/data.d.ts +81 -0
- package/dist/crdt/data.js +383 -0
- package/dist/crdt/document.d.ts +590 -0
- package/dist/crdt/document.js +1160 -0
- package/dist/crdt/edytor-doc.d.ts +752 -0
- package/dist/crdt/edytor-doc.js +2382 -0
- package/dist/crdt/engine-api.d.ts +153 -0
- package/dist/crdt/engine.d.ts +37 -0
- package/dist/crdt/engine.js +50 -0
- package/dist/crdt/flow.d.ts +104 -0
- package/dist/crdt/flow.js +229 -0
- package/dist/crdt/index.d.ts +630 -0
- package/dist/crdt/index.js +168 -0
- package/dist/crdt/migration/legacy-schema.d.ts +61 -0
- package/dist/crdt/migration/legacy-schema.js +149 -0
- package/dist/crdt/migration/migrate.d.ts +67 -0
- package/dist/crdt/migration/migrate.js +219 -0
- package/dist/crdt/nodes.d.ts +120 -0
- package/dist/crdt/nodes.js +56 -0
- package/dist/crdt/placement/model.d.ts +383 -0
- package/dist/crdt/placement/model.js +811 -0
- package/dist/crdt/placement/rank.d.ts +57 -0
- package/dist/crdt/placement/rank.js +209 -0
- package/dist/crdt/protocols/auth.d.ts +28 -0
- package/dist/crdt/protocols/auth.js +43 -0
- package/dist/crdt/protocols/awareness.d.ts +87 -0
- package/dist/crdt/protocols/awareness.js +271 -0
- package/dist/crdt/protocols/envelope.d.ts +75 -0
- package/dist/crdt/protocols/envelope.js +89 -0
- package/dist/crdt/protocols/observable.d.ts +19 -0
- package/dist/crdt/protocols/observable.js +26 -0
- package/dist/crdt/protocols/sync.d.ts +82 -0
- package/dist/crdt/protocols/sync.js +288 -0
- package/dist/crdt/providers/container.d.ts +23 -0
- package/dist/crdt/providers/container.js +64 -0
- package/dist/crdt/providers/index.d.ts +282 -0
- package/dist/crdt/providers/index.js +118 -0
- package/dist/crdt/providers/indexeddb.d.ts +196 -0
- package/dist/crdt/providers/indexeddb.js +332 -0
- package/dist/crdt/providers/room.d.ts +193 -0
- package/dist/crdt/providers/room.js +444 -0
- package/dist/crdt/providers/websocket.d.ts +223 -0
- package/dist/crdt/providers/websocket.js +601 -0
- package/dist/crdt/rand.d.ts +22 -0
- package/dist/crdt/rand.js +22 -0
- package/dist/crdt/rangeDelete.d.ts +85 -0
- package/dist/crdt/rangeDelete.js +126 -0
- package/dist/crdt/schema.d.ts +96 -0
- package/dist/crdt/schema.js +79 -0
- package/dist/crdt/semantics.d.ts +81 -0
- package/dist/crdt/semantics.js +57 -0
- package/dist/crdt/structs.d.ts +106 -0
- package/dist/crdt/structs.js +119 -0
- package/dist/crdt/text/deletes.d.ts +23 -0
- package/dist/crdt/text/deletes.js +608 -0
- package/dist/crdt/text/model.d.ts +280 -0
- package/dist/crdt/text/model.js +554 -0
- package/dist/crdt/text/runs.d.ts +212 -0
- package/dist/crdt/text/runs.js +1142 -0
- package/dist/crdt/vendor/yjs/API-NOTES.md +59 -0
- package/dist/crdt/vendor/yjs/LICENSE +23 -0
- package/dist/crdt/vendor/yjs/UPSTREAM.md +653 -0
- package/dist/crdt/vendor/yjs/dts/global.d.ts +52 -0
- package/dist/crdt/vendor/yjs/dts/index.d.ts +25 -0
- package/dist/crdt/vendor/yjs/dts/structs/AbstractStruct.d.ts +38 -0
- package/dist/crdt/vendor/yjs/dts/structs/GC.d.ts +25 -0
- package/dist/crdt/vendor/yjs/dts/structs/Item.d.ts +748 -0
- package/dist/crdt/vendor/yjs/dts/structs/Skip.d.ts +30 -0
- package/dist/crdt/vendor/yjs/dts/utils/BlockSet.d.ts +34 -0
- package/dist/crdt/vendor/yjs/dts/utils/Doc.d.ts +198 -0
- package/dist/crdt/vendor/yjs/dts/utils/EventHandler.d.ts +17 -0
- package/dist/crdt/vendor/yjs/dts/utils/ID.d.ts +20 -0
- package/dist/crdt/vendor/yjs/dts/utils/RangeCursor.d.ts +198 -0
- package/dist/crdt/vendor/yjs/dts/utils/RelativePosition.d.ts +80 -0
- package/dist/crdt/vendor/yjs/dts/utils/StructStore.d.ts +61 -0
- package/dist/crdt/vendor/yjs/dts/utils/Transaction.d.ts +129 -0
- package/dist/crdt/vendor/yjs/dts/utils/UndoManager.d.ts +205 -0
- package/dist/crdt/vendor/yjs/dts/utils/UpdateDecoder.d.ts +170 -0
- package/dist/crdt/vendor/yjs/dts/utils/UpdateEncoder.d.ts +164 -0
- package/dist/crdt/vendor/yjs/dts/utils/YEvent.d.ts +93 -0
- package/dist/crdt/vendor/yjs/dts/utils/content-helper.d.ts +1 -0
- package/dist/crdt/vendor/yjs/dts/utils/encoding-helpers.d.ts +5 -0
- package/dist/crdt/vendor/yjs/dts/utils/encoding.d.ts +26 -0
- package/dist/crdt/vendor/yjs/dts/utils/ids.d.ts +407 -0
- package/dist/crdt/vendor/yjs/dts/utils/isParentOf.d.ts +1 -0
- package/dist/crdt/vendor/yjs/dts/utils/meta.d.ts +25 -0
- package/dist/crdt/vendor/yjs/dts/utils/renderer-helpers.d.ts +98 -0
- package/dist/crdt/vendor/yjs/dts/utils/schemas.d.ts +2 -0
- package/dist/crdt/vendor/yjs/dts/utils/transaction-helpers.d.ts +15 -0
- package/dist/crdt/vendor/yjs/dts/utils/updates.d.ts +70 -0
- package/dist/crdt/vendor/yjs/dts/ynode.d.ts +655 -0
- package/dist/crdt/vendor/yjs/global.d.ts +52 -0
- package/dist/crdt/vendor/yjs/src/index.js +64 -0
- package/dist/crdt/vendor/yjs/src/structs/AbstractStruct.js +64 -0
- package/dist/crdt/vendor/yjs/src/structs/GC.js +75 -0
- package/dist/crdt/vendor/yjs/src/structs/Item.js +1538 -0
- package/dist/crdt/vendor/yjs/src/structs/Skip.js +72 -0
- package/dist/crdt/vendor/yjs/src/utils/BlockSet.js +291 -0
- package/dist/crdt/vendor/yjs/src/utils/Doc.js +255 -0
- package/dist/crdt/vendor/yjs/src/utils/EventHandler.js +75 -0
- package/dist/crdt/vendor/yjs/src/utils/ID.js +59 -0
- package/dist/crdt/vendor/yjs/src/utils/RangeCursor.js +407 -0
- package/dist/crdt/vendor/yjs/src/utils/RelativePosition.js +301 -0
- package/dist/crdt/vendor/yjs/src/utils/StructStore.js +134 -0
- package/dist/crdt/vendor/yjs/src/utils/Transaction.js +458 -0
- package/dist/crdt/vendor/yjs/src/utils/UndoManager.js +554 -0
- package/dist/crdt/vendor/yjs/src/utils/UpdateDecoder.js +284 -0
- package/dist/crdt/vendor/yjs/src/utils/UpdateEncoder.js +323 -0
- package/dist/crdt/vendor/yjs/src/utils/YEvent.js +158 -0
- package/dist/crdt/vendor/yjs/src/utils/content-helper.js +0 -0
- package/dist/crdt/vendor/yjs/src/utils/encoding-helpers.js +110 -0
- package/dist/crdt/vendor/yjs/src/utils/encoding.js +662 -0
- package/dist/crdt/vendor/yjs/src/utils/ids.js +1504 -0
- package/dist/crdt/vendor/yjs/src/utils/isParentOf.js +19 -0
- package/dist/crdt/vendor/yjs/src/utils/meta.js +74 -0
- package/dist/crdt/vendor/yjs/src/utils/renderer-helpers.js +186 -0
- package/dist/crdt/vendor/yjs/src/utils/schemas.js +3 -0
- package/dist/crdt/vendor/yjs/src/utils/transaction-helpers.js +391 -0
- package/dist/crdt/vendor/yjs/src/utils/updates.js +264 -0
- package/dist/crdt/vendor/yjs/src/ynode.js +2897 -0
- package/dist/dnd/pragmatic.d.ts +22 -0
- package/dist/dnd/pragmatic.js +26 -0
- package/dist/edytor.svelte.d.ts +323 -54
- package/dist/edytor.svelte.js +771 -197
- package/dist/edytor.utils.d.ts +49 -2
- package/dist/edytor.utils.js +65 -76
- package/dist/events/beforeInputCommands.d.ts +21 -0
- package/dist/events/beforeInputCommands.js +328 -0
- package/dist/events/beforeInputDeleteCommands.d.ts +3 -0
- package/dist/events/beforeInputDeleteCommands.js +245 -0
- package/dist/events/dataTransferPayload.d.ts +6 -0
- package/dist/events/dataTransferPayload.js +9 -0
- package/dist/events/domTextOffset.d.ts +12 -0
- package/dist/events/domTextOffset.js +52 -0
- package/dist/events/events.utils.d.ts +3 -0
- package/dist/events/events.utils.js +13 -0
- package/dist/events/nativeInteractiveControl.d.ts +31 -0
- package/dist/events/nativeInteractiveControl.js +98 -0
- package/dist/events/onBeforeInput.d.ts +10 -1
- package/dist/events/onBeforeInput.js +449 -330
- package/dist/events/onCopy.d.ts +7 -0
- package/dist/events/onCopy.js +30 -0
- package/dist/events/onCut.d.ts +8 -0
- package/dist/events/onCut.js +13 -0
- package/dist/events/onDrop.d.ts +16 -0
- package/dist/events/onDrop.js +158 -0
- package/dist/events/onFocus.d.ts +4 -0
- package/dist/events/onFocus.js +166 -0
- package/dist/events/onInput.d.ts +20 -0
- package/dist/events/onInput.js +249 -0
- package/dist/events/onKeyDown.js +191 -11
- package/dist/events/onPaste.d.ts +3 -0
- package/dist/events/onPaste.js +108 -0
- package/dist/events/wordBoundary.d.ts +2 -0
- package/dist/events/wordBoundary.js +58 -0
- package/dist/index.d.ts +38 -1
- package/dist/index.js +36 -1
- package/dist/kinds.d.ts +100 -0
- package/dist/kinds.js +198 -0
- package/dist/plugins/arrowMove/arrowMove.d.ts +1 -1
- package/dist/plugins/arrowMove/arrowMove.js +30 -65
- package/dist/plugins/blockHandles/BlockHandle.svelte +152 -0
- package/dist/plugins/blockHandles/BlockHandle.svelte.d.ts +12 -0
- package/dist/plugins/blockHandles/BlockHandleController.svelte.d.ts +208 -0
- package/dist/plugins/blockHandles/BlockHandleController.svelte.js +823 -0
- package/dist/plugins/blockHandles/BlockHandles.svelte +151 -0
- package/dist/plugins/blockHandles/BlockHandles.svelte.d.ts +20 -0
- package/dist/plugins/blockHandles/autoScroll.d.ts +8 -0
- package/dist/plugins/blockHandles/autoScroll.js +25 -0
- package/dist/plugins/blockHandles/blockHandlesPlugin.d.ts +37 -0
- package/dist/plugins/blockHandles/blockHandlesPlugin.js +100 -0
- package/dist/plugins/blockHandles/dragPreview.d.ts +33 -0
- package/dist/plugins/blockHandles/dragPreview.js +228 -0
- package/dist/plugins/blockMenu/BlockMenu.svelte +301 -0
- package/dist/plugins/blockMenu/BlockMenu.svelte.d.ts +9 -0
- package/dist/plugins/blockMenu/BlockMenuController.svelte.d.ts +102 -0
- package/dist/plugins/blockMenu/BlockMenuController.svelte.js +245 -0
- package/dist/plugins/blockMenu/blockMenuPlugin.d.ts +11 -0
- package/dist/plugins/blockMenu/blockMenuPlugin.js +89 -0
- package/dist/plugins/code/CodePlugin.svelte +210 -163
- package/dist/plugins/code/CodePlugin.svelte.d.ts +1 -3
- package/dist/plugins/code/code.css +92 -0
- package/dist/plugins/icons.d.ts +2 -0
- package/dist/plugins/icons.js +31 -0
- package/dist/plugins/image/ImageEmpty.svelte +69 -0
- package/dist/plugins/image/ImageEmpty.svelte.d.ts +8 -0
- package/dist/plugins/image/ImagePlugin.svelte +74 -12
- package/dist/plugins/image/ImagePlugin.svelte.d.ts +15 -0
- package/dist/plugins/image/image.d.ts +2 -0
- package/dist/plugins/image/image.js +7 -0
- package/dist/plugins/index.d.ts +14 -1
- package/dist/plugins/index.js +10 -1
- package/dist/plugins/keepInView.d.ts +4 -0
- package/dist/plugins/keepInView.js +6 -0
- package/dist/plugins/markdownShortcuts.d.ts +3 -0
- package/dist/plugins/markdownShortcuts.js +104 -0
- package/dist/plugins/mention/MentionPlugin.svelte +28 -31
- package/dist/plugins/richtext/RichTextPlugin.svelte +411 -200
- package/dist/plugins/richtext/RichTextPlugin.svelte.d.ts +8 -7
- package/dist/plugins/richtext/richTextOperations.d.ts +53 -0
- package/dist/plugins/richtext/richTextOperations.js +200 -0
- package/dist/plugins/slashMenu/SlashMenu.svelte +297 -0
- package/dist/plugins/slashMenu/SlashMenu.svelte.d.ts +11 -0
- package/dist/plugins/slashMenu/SlashMenuController.svelte.d.ts +56 -0
- package/dist/plugins/slashMenu/SlashMenuController.svelte.js +275 -0
- package/dist/plugins/slashMenu/slashMenuPlugin.d.ts +25 -0
- package/dist/plugins/slashMenu/slashMenuPlugin.js +105 -0
- package/dist/plugins/suggestions/SuggestionBars.svelte +142 -0
- package/dist/plugins/suggestions/SuggestionBars.svelte.d.ts +10 -0
- package/dist/plugins/suggestions/suggestionsPlugin.d.ts +28 -0
- package/dist/plugins/suggestions/suggestionsPlugin.js +53 -0
- package/dist/plugins/toolbar/Toolbar.svelte +341 -0
- package/dist/plugins/toolbar/Toolbar.svelte.d.ts +9 -0
- package/dist/plugins/toolbar/ToolbarController.svelte.d.ts +85 -0
- package/dist/plugins/toolbar/ToolbarController.svelte.js +150 -0
- package/dist/plugins/toolbar/toolbarPlugin.d.ts +16 -0
- package/dist/plugins/toolbar/toolbarPlugin.js +40 -0
- package/dist/plugins.d.ts +249 -40
- package/dist/plugins.js +11 -5
- package/dist/selection/domSelection.d.ts +29 -0
- package/dist/selection/domSelection.js +230 -0
- package/dist/selection/replaceSelection.d.ts +143 -0
- package/dist/selection/replaceSelection.js +316 -0
- package/dist/selection/selection.svelte.d.ts +275 -37
- package/dist/selection/selection.svelte.js +1162 -331
- package/dist/selection/selection.utils.d.ts +35 -4
- package/dist/selection/selection.utils.js +309 -100
- package/dist/selection/visibility.d.ts +88 -0
- package/dist/selection/visibility.js +140 -0
- package/dist/session/attempt.d.ts +190 -0
- package/dist/session/attempt.js +188 -0
- package/dist/session/bindings.d.ts +16 -0
- package/dist/session/bindings.js +262 -0
- package/dist/session/commands.d.ts +158 -0
- package/dist/session/commands.js +601 -0
- package/dist/session/composition.svelte.d.ts +114 -0
- package/dist/session/composition.svelte.js +489 -0
- package/dist/session/editing/text.d.ts +33 -0
- package/dist/session/editing/text.js +36 -0
- package/dist/session/handles.d.ts +63 -0
- package/dist/session/handles.js +123 -0
- package/dist/session/history.d.ts +49 -0
- package/dist/session/history.js +131 -0
- package/dist/session/keymap.d.ts +42 -0
- package/dist/session/keymap.js +144 -0
- package/dist/session/moves.d.ts +32 -0
- package/dist/session/moves.js +116 -0
- package/dist/session/navigation.d.ts +51 -0
- package/dist/session/navigation.js +312 -0
- package/dist/session/props.d.ts +28 -0
- package/dist/session/props.js +162 -0
- package/dist/session/selection.d.ts +126 -0
- package/dist/session/selection.js +227 -0
- package/dist/session/suggestions.svelte.d.ts +125 -0
- package/dist/session/suggestions.svelte.js +329 -0
- package/dist/session/virtual.d.ts +33 -0
- package/dist/session/virtual.js +182 -0
- package/dist/surface/attributes.d.ts +36 -0
- package/dist/surface/attributes.js +143 -0
- package/dist/surface/cells.d.ts +103 -0
- package/dist/surface/cells.js +215 -0
- package/dist/surface/observer.svelte.d.ts +70 -0
- package/dist/surface/observer.svelte.js +969 -0
- package/dist/surface/overlay.d.ts +33 -0
- package/dist/surface/overlay.js +91 -0
- package/dist/surface/pin.svelte.d.ts +56 -0
- package/dist/surface/pin.svelte.js +108 -0
- package/dist/surface/projector.svelte.d.ts +69 -0
- package/dist/surface/projector.svelte.js +486 -0
- package/dist/text/deltas.d.ts +14 -3
- package/dist/text/deltas.js +27 -90
- package/dist/text/text.svelte.d.ts +43 -31
- package/dist/text/text.svelte.js +88 -69
- package/dist/text/text.utils.d.ts +7 -2
- package/dist/text/text.utils.js +121 -97
- package/dist/themes/notion.css +473 -0
- package/dist/utils/diffText.d.ts +15 -0
- package/dist/utils/diffText.js +26 -0
- package/dist/utils/json.d.ts +90 -3
- package/dist/utils/json.js +369 -2
- package/dist/utils.d.ts +3 -1
- package/dist/utils.js +2 -0
- package/package.json +112 -50
- package/dist/block/content.svelte.d.ts +0 -14
- package/dist/block/content.svelte.js +0 -40
- package/dist/components/ReadonlyEditor.svelte +0 -46
- package/dist/components/ReadonlyEditor.svelte.d.ts +0 -4
- package/dist/components/readonlyElements.svelte.d.ts +0 -82
- package/dist/components/readonlyElements.svelte.js +0 -144
- package/dist/dnd.svelte.d.ts +0 -17
- package/dist/dnd.svelte.js +0 -125
- package/dist/hotkeys.d.ts +0 -27
- package/dist/hotkeys.js +0 -282
- package/dist/localProvider.d.ts +0 -82
- package/dist/localProvider.js +0 -267
- package/dist/plugins/code/prism.css +0 -141
- package/dist/utils/jsx.d.ts +0 -25
- package/dist/utils/jsx.js +0 -66
- package/dist/utils/serialize.js +0 -1
- /package/dist/{utils/serialize.d.ts → crdt/engine-api.js} +0 -0
|
@@ -1,499 +1,366 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { prevent } from '../utils.js';
|
|
1
|
+
import { id } from '../utils.js';
|
|
2
|
+
import { cloneJson, jsonBlockToSpec, jsonContentToItems } from '../utils/json.js';
|
|
4
3
|
import { InlineBlock } from './inlineBlock.svelte.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (normalizedPayload) {
|
|
18
|
-
finalPayload = normalizedPayload;
|
|
19
|
-
break;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
const result = this.edytor.transact(() => func.bind(this)(finalPayload));
|
|
23
|
-
for (const plugin of this.edytor.plugins) {
|
|
24
|
-
plugin.onAfterOperation?.({
|
|
25
|
-
operation,
|
|
26
|
-
payload,
|
|
27
|
-
block: this
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
return result;
|
|
4
|
+
/**
|
|
5
|
+
* Bind an operation onto its wrapper: every call is dispatched as a command
|
|
6
|
+
* (`session/commands.ts`): admission, hooks before any write (on the command
|
|
7
|
+
* and, when `prepare` answers one document plan, on each planned step), one
|
|
8
|
+
* transaction, normalization, the result. `func` receives the prepared plan
|
|
9
|
+
* and answers the op's document result; `resolve` turns it into wrappers
|
|
10
|
+
* after the commit patched them.
|
|
11
|
+
*/
|
|
12
|
+
export function batch(operation, func, prepare, resolve) {
|
|
13
|
+
return function (...[payload]) {
|
|
14
|
+
const out = this.edytor.dispatcher.dispatch(operation, payload, { block: this }, (p, plan) => func.call(this, p, plan), prepare && ((p) => prepare.call(this, p)));
|
|
15
|
+
return resolve ? resolve.call(this, out, payload) : out;
|
|
31
16
|
};
|
|
32
17
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
18
|
+
/**
|
|
19
|
+
* The handle of block `id` (null: refused at preparation, or gone; undefined:
|
|
20
|
+
* the command did not run). Inside an outer transaction too: the index shows
|
|
21
|
+
* the block that transaction created.
|
|
22
|
+
*/
|
|
23
|
+
export function blockOf(id) {
|
|
24
|
+
return id === undefined ? undefined : (id && this.edytor.idToBlock.get(id)) || null;
|
|
37
25
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
26
|
+
const REFUSED = { status: 'refused', ids: [] };
|
|
27
|
+
/**
|
|
28
|
+
* An op's body over its prepared plan: write it and request normalization of
|
|
29
|
+
* the blocks it touched (captured before the write). Answers the applied
|
|
30
|
+
* plan, or null when it was refused.
|
|
31
|
+
*/
|
|
32
|
+
const applyPlan = (block, plan, touched) => {
|
|
33
|
+
if (!('writes' in plan))
|
|
45
34
|
return null;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
35
|
+
block.edytor.facade.apply(plan);
|
|
36
|
+
for (const parent of touched)
|
|
37
|
+
parent?.normalizeChildren();
|
|
38
|
+
return plan;
|
|
39
|
+
};
|
|
40
|
+
/** The document's name for `block`'s child list: `null` for the root. */
|
|
41
|
+
const ref = (block) => (block.isRoot ? null : block.id);
|
|
42
|
+
/**
|
|
43
|
+
* Dispatch `operation` on `block` as the one plan `prepare` answers (a
|
|
44
|
+
* composed command: hooks see it and each planned step, one transaction).
|
|
45
|
+
* `then` runs in that transaction once the plan applied, with the payload
|
|
46
|
+
* hooks left. Answers the applied plan, or null when refused.
|
|
47
|
+
*/
|
|
48
|
+
export const dispatchPlan = (block, operation, payload, prepare, touched = [block.parent], then) => block.edytor.dispatcher.dispatch(operation, payload, { block }, (p, plan = prepare(p)) => {
|
|
49
|
+
const applied = applyPlan(block, plan, touched);
|
|
50
|
+
if (applied)
|
|
51
|
+
then?.(p);
|
|
52
|
+
return applied;
|
|
53
|
+
}, prepare) ?? null;
|
|
54
|
+
/** One child at `index` (a default-kind block without `block`); see {@link addChildBlocks}. */
|
|
55
|
+
export function addChildBlock({ block, index }) {
|
|
56
|
+
const blocks = [block || { type: this.edytor.defaultChild(this) }];
|
|
57
|
+
return addChildBlocks.call(this, { blocks, index })[0];
|
|
55
58
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
children: this.value.children
|
|
64
|
-
},
|
|
65
|
-
index: this.index
|
|
66
|
-
});
|
|
59
|
+
/** Children at `index`, clamped to the child list (at its end by default); ids kept or minted. */
|
|
60
|
+
export function addChildBlocks({ blocks, index = this.children.length }) {
|
|
61
|
+
index = Math.max(0, Math.min(index, this.children.length));
|
|
62
|
+
const specs = blocks.map((block) => ({ ...block, id: block.id ?? id('b') }));
|
|
63
|
+
this.insertChildren(index, specs);
|
|
64
|
+
this.normalizeChildren();
|
|
65
|
+
return specs.map((spec) => this.edytor.idToBlock.block(spec.id));
|
|
67
66
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const remainingContent = this.content.slice(indexOfContent + 1).map((part) => part.value);
|
|
75
|
-
const content = [splittedContent, ...remainingContent].flat();
|
|
76
|
-
const hasChildren = this.children.length >= 1;
|
|
77
|
-
// Add the current children to the new block if any
|
|
78
|
-
this.yContent.delete(indexOfContent + 1, this.content.length - indexOfContent - 1);
|
|
79
|
-
const newBlock = this.parent.addChildBlock({
|
|
80
|
-
block: {
|
|
81
|
-
type: this.edytor.getDefaultBlock(this.parent),
|
|
82
|
-
content,
|
|
83
|
-
children: this.value.children
|
|
84
|
-
},
|
|
85
|
-
index: this.parent.children.indexOf(this) + 1
|
|
86
|
-
});
|
|
87
|
-
// If the block has children, we need to remove its children and insert them into the new block
|
|
88
|
-
if (hasChildren) {
|
|
89
|
-
this.yChildren.delete(0, this.children.length);
|
|
90
|
-
}
|
|
91
|
-
return newBlock;
|
|
67
|
+
/** Insert `block` as a sibling of `this`, `after` it or before it. */
|
|
68
|
+
const prepareSibling = (self, block, after) => self.parent
|
|
69
|
+
? self.edytor.facade.prepare.insertBlocks({ parent: ref(self.parent), index: self.index + (after ? 1 : 0) }, [jsonBlockToSpec(block)])
|
|
70
|
+
: REFUSED;
|
|
71
|
+
export function prepareInsertAfter({ block }) {
|
|
72
|
+
return prepareSibling(this, block, true);
|
|
92
73
|
}
|
|
93
|
-
export function
|
|
94
|
-
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
// Get the current index from yChildren array since this.index may be stale when removing multiple blocks at once
|
|
98
|
-
const index = this.parent.yChildren.toArray().indexOf(this.yBlock);
|
|
99
|
-
if (this.yBlock._item?.deleted) {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
this.parent.yChildren.delete(index, 1);
|
|
103
|
-
if (keepChildren && this.hasChildren) {
|
|
104
|
-
this.parent.yChildren.insert(this.index, this.value.children.map((child) => {
|
|
105
|
-
const newBlock = new Block({
|
|
106
|
-
parent: this.parent,
|
|
107
|
-
edytor: this.edytor,
|
|
108
|
-
block: child
|
|
109
|
-
});
|
|
110
|
-
return newBlock.yBlock;
|
|
111
|
-
}));
|
|
112
|
-
}
|
|
74
|
+
export function prepareInsertBefore({ block }) {
|
|
75
|
+
return prepareSibling(this, block, false);
|
|
113
76
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
const { closestPreviousBlock, isEmpty } = this;
|
|
119
|
-
const { children = [] } = this.value;
|
|
120
|
-
if (!closestPreviousBlock) {
|
|
121
|
-
return this.isEmpty ? this.mergeBlockForward() : null;
|
|
122
|
-
}
|
|
123
|
-
// Add the current content to the previous block content
|
|
124
|
-
closestPreviousBlock.pushContentIntoBlock({ value: this.content });
|
|
125
|
-
if (!isEmpty) {
|
|
126
|
-
// If the current block has children, we need to unnest them and insert them into the current parent
|
|
127
|
-
if (children.length > 0) {
|
|
128
|
-
// Unnest children if any
|
|
129
|
-
this.parent.yChildren.insert(this.index, children.map((child) => {
|
|
130
|
-
const newBlock = new Block({
|
|
131
|
-
parent: this.parent,
|
|
132
|
-
edytor: this.edytor,
|
|
133
|
-
block: child
|
|
134
|
-
});
|
|
135
|
-
return newBlock.yBlock;
|
|
136
|
-
}));
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
// Remove the current block from its position
|
|
140
|
-
this.parent.yChildren.delete(this.index + this.children.length, 1);
|
|
141
|
-
return closestPreviousBlock;
|
|
77
|
+
/** Apply `plan` under `this`'s parent; the id it answers first (inserted or surviving). */
|
|
78
|
+
function resultOf(plan) {
|
|
79
|
+
return applyPlan(this, plan, [this.parent])?.ids[0] ?? null;
|
|
142
80
|
}
|
|
143
|
-
export function
|
|
144
|
-
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
const nextBlock = this.closestNextBlock;
|
|
148
|
-
if (!nextBlock) {
|
|
149
|
-
return null;
|
|
150
|
-
}
|
|
151
|
-
this.pushContentIntoBlock({ value: nextBlock.content });
|
|
152
|
-
if (nextBlock.children.length > 0 && nextBlock.parent) {
|
|
153
|
-
nextBlock.parent.yChildren.insert(nextBlock.index + 1, nextBlock.children.map((child) => {
|
|
154
|
-
const newBlock = new Block({
|
|
155
|
-
parent: nextBlock.parent,
|
|
156
|
-
edytor: this.edytor,
|
|
157
|
-
block: child.value
|
|
158
|
-
});
|
|
159
|
-
return newBlock.yBlock;
|
|
160
|
-
}));
|
|
161
|
-
}
|
|
162
|
-
nextBlock.parent?.yChildren.delete(nextBlock.index, 1);
|
|
163
|
-
return nextBlock;
|
|
81
|
+
export function insertBlockAfter(payload, plan = prepareInsertAfter.call(this, payload)) {
|
|
82
|
+
return resultOf.call(this, plan);
|
|
164
83
|
}
|
|
165
|
-
export function
|
|
166
|
-
|
|
167
|
-
return null;
|
|
168
|
-
}
|
|
169
|
-
const lastIndex = path.pop();
|
|
170
|
-
let currentBlock = this.edytor.root;
|
|
171
|
-
while (path.length > 0) {
|
|
172
|
-
const index = path.shift();
|
|
173
|
-
if (typeof index !== 'number' || isNaN(index))
|
|
174
|
-
break;
|
|
175
|
-
currentBlock = currentBlock.children[index];
|
|
176
|
-
}
|
|
177
|
-
if (!currentBlock) {
|
|
178
|
-
return null;
|
|
179
|
-
}
|
|
180
|
-
this.edytor.idToBlock.delete(this.id);
|
|
181
|
-
this.parent.yChildren.delete(this.index, 1);
|
|
182
|
-
const newBlock = new Block({
|
|
183
|
-
parent: currentBlock,
|
|
184
|
-
edytor: this.edytor,
|
|
185
|
-
block: this.value
|
|
186
|
-
});
|
|
187
|
-
currentBlock.yChildren.insert(lastIndex, [newBlock.yBlock]);
|
|
188
|
-
return newBlock;
|
|
84
|
+
export function insertBlockBefore(payload, plan = prepareInsertBefore.call(this, payload)) {
|
|
85
|
+
return resultOf.call(this, plan);
|
|
189
86
|
}
|
|
190
|
-
export function
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
const grandParent = parent.parent;
|
|
196
|
-
if (!grandParent) {
|
|
197
|
-
return null;
|
|
198
|
-
}
|
|
199
|
-
const newBlock = new Block({
|
|
200
|
-
parent: grandParent,
|
|
201
|
-
edytor: this.edytor,
|
|
202
|
-
block: this.value
|
|
203
|
-
});
|
|
204
|
-
grandParent.yChildren.insert(parent.index + 1, [newBlock.yBlock]);
|
|
205
|
-
parent.yChildren.delete(index, 1);
|
|
206
|
-
return newBlock;
|
|
207
|
-
}
|
|
208
|
-
export function nestBlock() {
|
|
209
|
-
const previousBlock = this.previousBlock;
|
|
210
|
-
if (!previousBlock ||
|
|
211
|
-
previousBlock?.definition?.void ||
|
|
212
|
-
previousBlock?.definition?.island ||
|
|
213
|
-
!this.parent) {
|
|
214
|
-
return null;
|
|
215
|
-
}
|
|
216
|
-
const newBlock = new Block({
|
|
217
|
-
parent: previousBlock,
|
|
218
|
-
edytor: this.edytor,
|
|
219
|
-
block: { ...this.value, children: [] }
|
|
220
|
-
});
|
|
221
|
-
previousBlock.yChildren.insert(previousBlock.children.length, [newBlock.yBlock]);
|
|
222
|
-
if (this.value.children && this.value.children.length) {
|
|
223
|
-
previousBlock.yChildren.insert(previousBlock.children.length + 1, this.value.children.map((child) => {
|
|
224
|
-
const newBlock = new Block({
|
|
225
|
-
parent: previousBlock,
|
|
226
|
-
edytor: this.edytor,
|
|
227
|
-
block: child
|
|
228
|
-
});
|
|
229
|
-
return newBlock.yBlock;
|
|
230
|
-
}));
|
|
231
|
-
}
|
|
232
|
-
this.parent.yChildren.delete(this.index, 1);
|
|
233
|
-
return newBlock;
|
|
87
|
+
export function prepareDuplicate() {
|
|
88
|
+
if (!this.parent || !this.isInTree)
|
|
89
|
+
return REFUSED;
|
|
90
|
+
return this.edytor.facade.prepare.duplicateBlock(this.id, (_, kind) => id(kind === 'block' ? 'b' : 'i'));
|
|
234
91
|
}
|
|
235
|
-
export function
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
92
|
+
export function duplicateBlock(_ = {}, plan = prepareDuplicate.call(this)) {
|
|
93
|
+
return resultOf.call(this, plan);
|
|
94
|
+
}
|
|
95
|
+
export function prepareSplit({ index, text }) {
|
|
96
|
+
if (!text || !this.parent || !this.model)
|
|
97
|
+
return REFUSED;
|
|
98
|
+
// G5: the sibling takes its parent's default child type and no data — a
|
|
99
|
+
// list-like kind (`continues`) keeps its own, with its first preset's data.
|
|
100
|
+
const { continues, presets } = this.definition;
|
|
101
|
+
const tail = continues
|
|
102
|
+
? { type: this.type, data: { ...(presets?.[0]?.data ?? {}) } }
|
|
103
|
+
: { type: this.edytor.defaultChild(this.parent), data: {} };
|
|
104
|
+
const offset = text.segStart + index;
|
|
105
|
+
return this.edytor.facade.prepare.splitBlock(this.model.id, offset, id('b'), tail);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* A split whose children stay with the block (a container's header): the
|
|
109
|
+
* tail, of `tail`'s kind, becomes the block's first child (`child`) or its
|
|
110
|
+
* next sibling. One plan: the document's split step, placed here, without
|
|
111
|
+
* the move that gives the tail the children.
|
|
112
|
+
*/
|
|
113
|
+
export function prepareSplitKeepingChildren({ index, text }, tail, child) {
|
|
114
|
+
if (!text || !this.parent || !this.model)
|
|
115
|
+
return REFUSED;
|
|
116
|
+
const { facade } = this.edytor;
|
|
117
|
+
const born = id('b');
|
|
118
|
+
const split = facade.prepare.splitBlock(this.model.id, text.segStart + index, born, tail);
|
|
119
|
+
const step = 'writes' in split ? split.writes[0] : undefined;
|
|
120
|
+
if (step?.op !== 'splitBlock')
|
|
121
|
+
return REFUSED;
|
|
122
|
+
if (!child)
|
|
123
|
+
return facade.compose({ ...split, writes: [step] });
|
|
124
|
+
// The rank of a first child, and the document's answer on placing the kind there.
|
|
125
|
+
const slot = facade.prepare.insertBlocks({ parent: this.model.id, index: 0 }, [
|
|
126
|
+
{ id: born, type: tail.type }
|
|
127
|
+
]);
|
|
128
|
+
const first = 'writes' in slot ? slot.writes[0] : undefined;
|
|
129
|
+
if (first?.op !== 'insertBlocks')
|
|
130
|
+
return REFUSED;
|
|
131
|
+
const placed = { ...step, parent: this.model.id, rank: first.ranks[0] };
|
|
132
|
+
return facade.compose({ ...split, writes: [placed] });
|
|
133
|
+
}
|
|
134
|
+
export function splitBlock(payload, plan = prepareSplit.call(this, payload)) {
|
|
135
|
+
return applyPlan(this, plan, [this.parent])?.effect.creates[0] ?? null;
|
|
136
|
+
}
|
|
137
|
+
export function prepareRemove({ keepChildren = true } = {}) {
|
|
138
|
+
if (!this.parent || !this.model || !this.isInTree)
|
|
139
|
+
return REFUSED;
|
|
140
|
+
return this.edytor.facade.prepare.deleteBlock(this.model.id, { keepChildren });
|
|
141
|
+
}
|
|
142
|
+
export function removeBlock(payload = {}, plan = prepareRemove.call(this, payload)) {
|
|
143
|
+
applyPlan(this, plan, [this.parent]);
|
|
144
|
+
}
|
|
145
|
+
export function prepareMergeBackward() {
|
|
146
|
+
return this.parent && this.model
|
|
147
|
+
? this.edytor.facade.prepare.mergeBackward(this.model.id)
|
|
148
|
+
: REFUSED;
|
|
149
|
+
}
|
|
150
|
+
export function prepareMergeForward() {
|
|
151
|
+
return this.parent && this.model
|
|
152
|
+
? this.edytor.facade.prepare.mergeForward(this.model.id)
|
|
153
|
+
: REFUSED;
|
|
154
|
+
}
|
|
155
|
+
export function mergeBlockBackward(_ = {}, plan = prepareMergeBackward.call(this)) {
|
|
156
|
+
return resultOf.call(this, plan);
|
|
157
|
+
}
|
|
158
|
+
export function mergeBlockForward(_ = {}, plan = prepareMergeForward.call(this)) {
|
|
159
|
+
return resultOf.call(this, plan);
|
|
160
|
+
}
|
|
161
|
+
/** The destination parent a view-tree path (`[...parentPath, index]`) names. */
|
|
162
|
+
const parentAt = (edytor, path) => {
|
|
163
|
+
let parent = edytor.root;
|
|
164
|
+
for (const index of path.slice(0, -1))
|
|
165
|
+
parent = parent?.children[index];
|
|
166
|
+
return [parent, path.at(-1)];
|
|
167
|
+
};
|
|
168
|
+
export function prepareMove({ path }) {
|
|
169
|
+
// Admission: the caller path is a view-tree address — validate its shape
|
|
170
|
+
// and resolve it to the destination PARENT block + index. Structural
|
|
171
|
+
// permission is the document's (`canPlace`: island seals, void/island
|
|
172
|
+
// destinations, moves into the block's own subtree).
|
|
173
|
+
if (!path.length || path.some((p) => isNaN(p) || p < 0) || !this.parent)
|
|
174
|
+
return REFUSED;
|
|
175
|
+
const [parent, index] = parentAt(this.edytor, path);
|
|
176
|
+
if (!parent || !this.model)
|
|
177
|
+
return REFUSED;
|
|
178
|
+
return this.edytor.facade.prepare.moveBlock(this.model.id, { parent: ref(parent), index });
|
|
179
|
+
}
|
|
180
|
+
export function moveBlock(payload, plan = prepareMove.call(this, payload)) {
|
|
181
|
+
return applyPlan(this, plan, [this.parent, parentAt(this.edytor, payload.path)[0]]) ? this : null;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Grouped move — the operation-layer counterpart of `moveBlock` for
|
|
185
|
+
* drags/multi-moves (D5). `path` is the same view-tree address shape:
|
|
186
|
+
* the prefix resolves the destination PARENT block, the last element is
|
|
187
|
+
* the FINAL index — already discounted for the moved members by the
|
|
188
|
+
* caller (the `facade.moveBlocks` contract, which counts the
|
|
189
|
+
* destination's children with the moved members excluded). Structural
|
|
190
|
+
* permission stays in the facade.
|
|
191
|
+
*/
|
|
192
|
+
export function prepareMoves({ blocks, path }) {
|
|
193
|
+
if (!path.length || path.some((p) => isNaN(p) || p < 0) || !blocks.length)
|
|
194
|
+
return REFUSED;
|
|
195
|
+
const [parent, index] = parentAt(this.edytor, path);
|
|
196
|
+
if (!parent || blocks.some((block) => block.isRoot))
|
|
197
|
+
return REFUSED;
|
|
198
|
+
return this.edytor.facade.prepare.moveBlocks(blocks.map((block) => block.id), { parent: ref(parent), index });
|
|
199
|
+
}
|
|
200
|
+
export function moveBlocks(payload, plan = prepareMoves.call(this, payload)) {
|
|
201
|
+
const { blocks, path } = payload;
|
|
202
|
+
const parents = new Set([...blocks.map((block) => block.parent), parentAt(this.edytor, path)[0]]);
|
|
203
|
+
return applyPlan(this, plan, [...parents]) ? blocks : [];
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* The facade owns the refusal rules (`unNestBlock`: top-level blocks,
|
|
207
|
+
* island-sealed blocks and sealed destinations).
|
|
208
|
+
*/
|
|
209
|
+
export function prepareUnNest() {
|
|
210
|
+
return this.parent && this.model
|
|
211
|
+
? this.edytor.facade.prepare.unNestBlock(this.model.id)
|
|
212
|
+
: REFUSED;
|
|
213
|
+
}
|
|
214
|
+
export function unNestBlock(_ = {}, plan = prepareUnNest.call(this)) {
|
|
215
|
+
return applyPlan(this, plan, [this.parent, this.parent?.parent, this]) ? this : null;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Admission resolves the nest target — the previous sibling — and the
|
|
219
|
+
* facade owns permission: `nestBlock` refuses void/island/inside-island
|
|
220
|
+
* targets and island-sealed sources (`canPlace`).
|
|
221
|
+
*/
|
|
222
|
+
export function prepareNest() {
|
|
223
|
+
const target = this.previousBlock?.id;
|
|
224
|
+
return this.parent && this.model && target != null
|
|
225
|
+
? this.edytor.facade.prepare.nestBlock(this.model.id, target)
|
|
226
|
+
: REFUSED;
|
|
227
|
+
}
|
|
228
|
+
export function nestBlock(_ = {}, plan = prepareNest.call(this)) {
|
|
229
|
+
return applyPlan(this, plan, [this.parent, this.previousBlock]) ? this : null;
|
|
230
|
+
}
|
|
231
|
+
export function prepareSet({ value }) {
|
|
232
|
+
if (!this.model)
|
|
233
|
+
return REFUSED;
|
|
234
|
+
// Spec preparation is pure JSON → `ContentItem`/`BlockSpec` conversion:
|
|
235
|
+
// the document stores the items verbatim and derives the content
|
|
236
|
+
// invariant on projection.
|
|
237
|
+
return this.edytor.facade.prepare.setBlock(this.model.id, {
|
|
238
|
+
...(value.type !== undefined ? { type: value.type } : {}),
|
|
239
|
+
...(value.data !== undefined ? { data: cloneJson(value.data) } : {}),
|
|
240
|
+
...(value.content !== undefined ? { content: jsonContentToItems(value.content) } : {}),
|
|
241
|
+
...(value.children !== undefined
|
|
242
|
+
? { children: value.children.map((child) => jsonBlockToSpec(child)) }
|
|
243
|
+
: {})
|
|
288
244
|
});
|
|
289
245
|
}
|
|
246
|
+
export function setBlock(payload, plan = prepareSet.call(this, payload)) {
|
|
247
|
+
if (!applyPlan(this, plan, [this]))
|
|
248
|
+
return;
|
|
249
|
+
this.normalizeContent();
|
|
250
|
+
}
|
|
290
251
|
export function pushContentIntoBlock({ value }) {
|
|
291
|
-
const
|
|
292
|
-
|
|
252
|
+
const model = this.model;
|
|
253
|
+
if (!model)
|
|
254
|
+
return;
|
|
293
255
|
for (const part of value) {
|
|
294
256
|
if (part instanceof InlineBlock) {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
parent: this,
|
|
298
|
-
block: part
|
|
299
|
-
});
|
|
300
|
-
this.yContent.insert(index, [newInlineBlock.yBlock]);
|
|
301
|
-
index++;
|
|
257
|
+
const { id, type, data } = part;
|
|
258
|
+
model.insertInline(model.length, { id, type, ...(data ? { data: cloneJson(data) } : {}) });
|
|
302
259
|
}
|
|
303
260
|
else {
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
lastPart.yText.applyDelta([{ retain: lastPart.yText.length }, ...delta]);
|
|
308
|
-
}
|
|
309
|
-
else {
|
|
310
|
-
const newText = new Text({
|
|
311
|
-
parent: this,
|
|
312
|
-
content: part.value
|
|
313
|
-
});
|
|
314
|
-
this.yContent.insert(index, [newText.yText]);
|
|
315
|
-
index++;
|
|
316
|
-
}
|
|
261
|
+
for (const { text, marks } of part.value)
|
|
262
|
+
if (text.length)
|
|
263
|
+
model.insertText(model.length, text, marks);
|
|
317
264
|
}
|
|
318
265
|
}
|
|
319
|
-
|
|
266
|
+
this.normalizeContent();
|
|
320
267
|
}
|
|
321
|
-
export function
|
|
268
|
+
export function prepareRemoveInline({ index }) {
|
|
322
269
|
const part = this.content.at(index);
|
|
323
|
-
|
|
324
|
-
this.
|
|
270
|
+
return part instanceof InlineBlock && this.model
|
|
271
|
+
? this.edytor.facade.prepare.removeInline(this.model.id, part.id)
|
|
272
|
+
: REFUSED;
|
|
273
|
+
}
|
|
274
|
+
export function removeInlineBlock(payload, plan = prepareRemoveInline.call(this, payload)) {
|
|
275
|
+
if (applyPlan(this, plan, []))
|
|
325
276
|
this.normalizeContent();
|
|
326
|
-
}
|
|
327
277
|
}
|
|
328
|
-
export
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
acc.push([{ text: '' }]);
|
|
341
|
-
}
|
|
342
|
-
acc.push(part);
|
|
343
|
-
}
|
|
344
|
-
else {
|
|
345
|
-
const lastPart = acc.at(-1);
|
|
346
|
-
if (acc.length && lastPart && Array.isArray(lastPart)) {
|
|
347
|
-
lastPart.push(part);
|
|
348
|
-
}
|
|
349
|
-
else {
|
|
350
|
-
acc.push([part]);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
return acc;
|
|
354
|
-
}, []);
|
|
355
|
-
if (isInlineJSONBlock(groupedContent.at(0))) {
|
|
356
|
-
// Make sure that the first part is an inline block
|
|
357
|
-
groupedContent.unshift([{ text: '' }]);
|
|
358
|
-
}
|
|
359
|
-
if (isInlineJSONBlock(groupedContent.at(-1))) {
|
|
360
|
-
// Make sure that the last part is a text block
|
|
361
|
-
groupedContent.push([{ text: '' }]);
|
|
362
|
-
}
|
|
363
|
-
return groupedContent;
|
|
364
|
-
};
|
|
278
|
+
export function preparePatch({ ops, atom }) {
|
|
279
|
+
const target = this.isRoot ? null : atom === undefined ? this.id : { block: this.id, atom };
|
|
280
|
+
return this.edytor.facade.prepare.patchData(target, ops);
|
|
281
|
+
}
|
|
282
|
+
export function patchData(payload, plan = preparePatch.call(this, payload)) {
|
|
283
|
+
applyPlan(this, plan, []);
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Insert an inline atom at `index` of `text`. Answers the atom's id; the
|
|
287
|
+
* batched operation resolves it to the text after the atom once committed
|
|
288
|
+
* ({@link textAfterAtom}), where the caret's pending marks follow.
|
|
289
|
+
*/
|
|
365
290
|
export function addInlineBlock({ index, block, text }) {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
const newText = new Text({
|
|
372
|
-
parent: this,
|
|
373
|
-
content: text.splitText({ index })
|
|
291
|
+
const atom = { ...block, id: block.id ?? id('i') };
|
|
292
|
+
this.model?.insertInline(text.segStart + index, {
|
|
293
|
+
id: atom.id,
|
|
294
|
+
type: atom.type,
|
|
295
|
+
...(atom.data ? { data: cloneJson(atom.data) } : {})
|
|
374
296
|
});
|
|
375
|
-
this.yContent.insert(text.index + 1, [newInlineBlock.yBlock, newText.yText]);
|
|
376
297
|
this.normalizeContent();
|
|
377
|
-
return
|
|
298
|
+
return atom.id;
|
|
378
299
|
}
|
|
300
|
+
/** The text after atom `atom` of this block; the caret's pending marks follow it there (L4). */
|
|
301
|
+
export function textAfterAtom(atom) {
|
|
302
|
+
if (atom === undefined)
|
|
303
|
+
return undefined;
|
|
304
|
+
const at = this.content.findIndex((part) => part.id === atom);
|
|
305
|
+
const after = at < 0 ? undefined : this.content[at + 1];
|
|
306
|
+
if (!after || after instanceof InlineBlock)
|
|
307
|
+
return null;
|
|
308
|
+
const { selection } = this.edytor;
|
|
309
|
+
const pending = selection.pending;
|
|
310
|
+
const caret = pending && selection.textValue(after, 0);
|
|
311
|
+
if (caret && caret.kind === 'text')
|
|
312
|
+
selection.select(Object.freeze({ ...caret, pending }));
|
|
313
|
+
return after;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Normalization runs at the end of the command's transaction
|
|
317
|
+
* (`Dispatcher.drain`): a normalizer reads handles over the index; when a
|
|
318
|
+
* plugin hook answers work, the work runs in the same transaction and the
|
|
319
|
+
* block is requested again (bounded by the dispatcher's pass limit, D25).
|
|
320
|
+
*/
|
|
379
321
|
export function normalizeContent() {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
this.
|
|
388
|
-
return this.normalizeContent();
|
|
389
|
-
}
|
|
390
|
-
// Ensure content ends with Text
|
|
391
|
-
if (!(content[content.length - 1] instanceof Y.Text)) {
|
|
392
|
-
const emptyText = new Text({
|
|
393
|
-
parent: this,
|
|
394
|
-
content: [{ text: '' }]
|
|
395
|
-
});
|
|
396
|
-
this.yContent.insert(content.length, [emptyText.yText]);
|
|
397
|
-
return this.normalizeContent();
|
|
398
|
-
}
|
|
399
|
-
// First handle consecutive text blocks
|
|
400
|
-
const consecutiveTexts = content.reduce((acc, part, index) => {
|
|
401
|
-
const nextPart = content[index + 1];
|
|
402
|
-
if (part instanceof Y.Text && nextPart instanceof Y.Text) {
|
|
403
|
-
acc.push([part, nextPart]);
|
|
404
|
-
}
|
|
405
|
-
return acc;
|
|
406
|
-
}, []);
|
|
407
|
-
if (consecutiveTexts.length > 0) {
|
|
408
|
-
const [first, second] = consecutiveTexts[0];
|
|
409
|
-
const delta = second.toDelta();
|
|
410
|
-
first.applyDelta([{ retain: first.length }, ...delta]);
|
|
411
|
-
this.yContent.delete(content.indexOf(second), 1);
|
|
412
|
-
return this.normalizeContent();
|
|
413
|
-
}
|
|
414
|
-
// Then handle consecutive inline blocks
|
|
415
|
-
const consecutiveInlineBlocks = content.reduce((acc, part, index) => {
|
|
416
|
-
const nextPart = content[index + 1];
|
|
417
|
-
if (part instanceof Y.Map && nextPart instanceof Y.Map) {
|
|
418
|
-
acc.push([part, nextPart]);
|
|
419
|
-
}
|
|
420
|
-
return acc;
|
|
421
|
-
}, []);
|
|
422
|
-
if (consecutiveInlineBlocks.length > 0) {
|
|
423
|
-
const [first, second] = consecutiveInlineBlocks[0];
|
|
424
|
-
const emptyText = new Text({
|
|
425
|
-
parent: this,
|
|
426
|
-
content: [{ text: '' }]
|
|
427
|
-
});
|
|
428
|
-
const index = content.indexOf(second);
|
|
429
|
-
this.yContent.insert(index, [emptyText.yText]);
|
|
430
|
-
return this.normalizeContent();
|
|
431
|
-
}
|
|
432
|
-
const pluginNormalization = this.definition?.normalizeContent?.({ block: this });
|
|
433
|
-
if (pluginNormalization) {
|
|
434
|
-
pluginNormalization();
|
|
322
|
+
if (this.edytor.dispatcher.defer(this, normalizeContent))
|
|
323
|
+
return;
|
|
324
|
+
// The v14 content model maintains the part invariants by construction —
|
|
325
|
+
// projected content always derives to text-first/text-last/non-adjacent
|
|
326
|
+
// parts — so the only remaining normalization is the plugin hook.
|
|
327
|
+
const work = this.definition?.normalizeContent?.({ block: this });
|
|
328
|
+
if (work) {
|
|
329
|
+
this.edytor.dispatcher.write(work);
|
|
435
330
|
this.normalizeContent();
|
|
436
331
|
}
|
|
437
332
|
}
|
|
438
|
-
export function
|
|
439
|
-
if (
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
this.suggestions = null;
|
|
333
|
+
export function normalizeChildren() {
|
|
334
|
+
if (this.edytor.dispatcher.defer(this, normalizeChildren))
|
|
335
|
+
return;
|
|
336
|
+
// An emptied root writes nothing: the view shows its virtual paragraph (`doc.empty.virtual`).
|
|
337
|
+
const work = this.definition?.normalizeChildren?.({ block: this });
|
|
338
|
+
if (work) {
|
|
339
|
+
this.edytor.dispatcher.write(work);
|
|
340
|
+
this.normalizeChildren();
|
|
447
341
|
}
|
|
448
342
|
}
|
|
343
|
+
/** @deprecated A thin wrapper over an `{ end: block.id }` suggestion (`edytor.suggestions`). */
|
|
344
|
+
export function suggestText({ value }) {
|
|
345
|
+
this.suggestions =
|
|
346
|
+
typeof value === 'string'
|
|
347
|
+
? [[{ text: value }]]
|
|
348
|
+
: (value?.map((part) => ('type' in part ? part : [part])) ?? null);
|
|
349
|
+
}
|
|
350
|
+
/** @deprecated Accepts this block's latest `{ end }` suggestion (`suggestion.accept()`). */
|
|
449
351
|
export function acceptSuggestedText() {
|
|
450
|
-
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
const editableSuggestions = this.suggestions.map((part) => {
|
|
454
|
-
if ('type' in part) {
|
|
455
|
-
return new InlineBlock({
|
|
456
|
-
parent: this,
|
|
457
|
-
block: part.value
|
|
458
|
-
});
|
|
459
|
-
}
|
|
460
|
-
else {
|
|
461
|
-
return new Text({
|
|
462
|
-
parent: this,
|
|
463
|
-
content: part.value
|
|
464
|
-
});
|
|
465
|
-
}
|
|
466
|
-
});
|
|
467
|
-
this.yContent.insert(this.content.length, editableSuggestions.map((suggestion) => 'yBlock' in suggestion ? suggestion.yBlock : suggestion.yText));
|
|
468
|
-
this.suggestions = null;
|
|
469
|
-
this.normalizeContent();
|
|
352
|
+
this.edytor.suggestions.at(this.id).end.at(-1)?.accept();
|
|
470
353
|
}
|
|
471
|
-
export function
|
|
472
|
-
const
|
|
473
|
-
const [
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
else if (isLastPart) {
|
|
484
|
-
// Delete from start to offset
|
|
485
|
-
part.yText.delete(0, endOffset);
|
|
486
|
-
}
|
|
487
|
-
else {
|
|
488
|
-
numberToDelete++;
|
|
489
|
-
// Delete entire text element
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
else {
|
|
493
|
-
// For inline blocks, always delete the entire element
|
|
494
|
-
numberToDelete++;
|
|
495
|
-
}
|
|
496
|
-
});
|
|
497
|
-
this.yContent.delete(startIndex + 1, numberToDelete);
|
|
498
|
-
this.normalizeContent();
|
|
354
|
+
export function prepareDeleteRange({ start: [startIndex, startOffset], end: [endIndex, endOffset] }) {
|
|
355
|
+
const parts = this.edytor.idToBlock.parts(this.id);
|
|
356
|
+
const [startPart, endPart] = [parts.at(startIndex), parts.at(endIndex)];
|
|
357
|
+
if (!startPart || !endPart || !this.model)
|
|
358
|
+
return REFUSED;
|
|
359
|
+
const at = startPart.start + startOffset;
|
|
360
|
+
const length = Math.max(0, endPart.start + endOffset - at);
|
|
361
|
+
return this.edytor.facade.prepare.deleteText(this.model.id, at, length);
|
|
362
|
+
}
|
|
363
|
+
export function deleteContentAtRange(payload, plan = prepareDeleteRange.call(this, payload)) {
|
|
364
|
+
if (applyPlan(this, plan, []))
|
|
365
|
+
this.normalizeContent();
|
|
499
366
|
}
|