@ecsplico/editor 2.1.2 → 3.0.0
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/CHANGELOG.md +68 -1
- package/README.md +39 -156
- package/dist/adapters/comments/drizzle.d.ts +1 -1
- package/dist/adapters/comments/{client.js → rest-model.js} +3 -3
- package/dist/adapters/comments/rest-model.js.map +1 -0
- package/dist/adapters/comments/types.d.ts +2 -2
- package/dist/adapters/document-state.d.ts +23 -0
- package/dist/adapters/document-state.js +66 -0
- package/dist/adapters/document-state.js.map +1 -0
- package/dist/adapters/documents.js +14 -11
- package/dist/adapters/documents.js.map +1 -1
- package/dist/adapters/drizzle.d.ts +2 -2
- package/dist/adapters/drizzle.js +97 -88
- package/dist/adapters/drizzle.js.map +1 -1
- package/dist/adapters/forge.d.ts +12 -7
- package/dist/adapters/forge.js +38 -45
- package/dist/adapters/forge.js.map +1 -1
- package/dist/adapters/http.d.ts +20 -0
- package/dist/adapters/http.js +68 -0
- package/dist/adapters/http.js.map +1 -0
- package/dist/adapters/index.d.ts +5 -5
- package/dist/adapters/json.d.ts +3 -3
- package/dist/adapters/json.js +58 -49
- package/dist/adapters/json.js.map +1 -1
- package/dist/adapters/memory.d.ts +21 -0
- package/dist/adapters/memory.js +53 -0
- package/dist/adapters/memory.js.map +1 -0
- package/dist/adapters/nitro.d.ts +23 -20
- package/dist/adapters/nitro.js +58 -163
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/react.d.ts +55 -0
- package/dist/adapters/react.js +209 -0
- package/dist/adapters/react.js.map +1 -0
- package/dist/adapters/shared.d.ts +15 -21
- package/dist/adapters/shared.js +10 -8
- package/dist/adapters/shared.js.map +1 -1
- package/dist/adapters/vue.d.ts +15 -30
- package/dist/adapters/vue.js +36 -87
- package/dist/adapters/vue.js.map +1 -1
- package/dist/config/index.d.ts +105 -0
- package/dist/config/index.js +95 -0
- package/dist/config/index.js.map +1 -0
- package/dist/core/abilities.js +1 -0
- package/dist/core/abilities.js.map +1 -1
- package/dist/{adapters/routes.js → core/api-routes.js} +5 -3
- package/dist/core/api-routes.js.map +1 -0
- package/dist/core/backend-capability.d.ts +7 -0
- package/dist/core/backend-capability.js +17 -0
- package/dist/core/backend-capability.js.map +1 -0
- package/dist/core/backend-types.d.ts +245 -0
- package/dist/core/backend-types.js +17 -0
- package/dist/core/backend-types.js.map +1 -0
- package/dist/core/backend.d.ts +108 -0
- package/dist/core/backend.js +14 -0
- package/dist/core/backend.js.map +1 -0
- package/dist/core/block-convert.d.ts +7 -5
- package/dist/core/block-convert.js +28 -5
- package/dist/core/block-convert.js.map +1 -1
- package/dist/core/command-types.d.ts +89 -0
- package/dist/core/commands.d.ts +40 -0
- package/dist/core/commands.js +151 -0
- package/dist/core/commands.js.map +1 -0
- package/dist/core/context.d.ts +17 -20
- package/dist/core/context.js +24 -21
- package/dist/core/context.js.map +1 -1
- package/dist/core/core-feature.d.ts +22 -7
- package/dist/core/core-feature.js +51 -18
- package/dist/core/core-feature.js.map +1 -1
- package/dist/core/define-editor.d.ts +4 -3
- package/dist/core/define-editor.js +14 -7
- package/dist/core/define-editor.js.map +1 -1
- package/dist/core/document-markdown.js +12 -3
- package/dist/core/document-markdown.js.map +1 -1
- package/dist/core/editor-ui.d.ts +8 -1
- package/dist/core/editor-ui.js +9 -8
- package/dist/core/editor-ui.js.map +1 -1
- package/dist/core/extension-points.d.ts +3 -15
- package/dist/core/feature-context.d.ts +8 -7
- package/dist/core/feature-context.js +12 -11
- package/dist/core/feature-context.js.map +1 -1
- package/dist/core/feature.d.ts +35 -19
- package/dist/core/feature.js.map +1 -1
- package/dist/core/fences.d.ts +2 -1
- package/dist/core/fences.js +3 -2
- package/dist/core/fences.js.map +1 -1
- package/dist/core/fetch-error.d.ts +1 -1
- package/dist/core/fetch-error.js +3 -1
- package/dist/core/fetch-error.js.map +1 -1
- package/dist/core/hash.d.ts +5 -0
- package/dist/core/hash.js +11 -0
- package/dist/core/hash.js.map +1 -0
- package/dist/core/http-backend.d.ts +11 -0
- package/dist/core/http-backend.js +195 -0
- package/dist/core/http-backend.js.map +1 -0
- package/dist/core/index.d.ts +14 -9
- package/dist/core/index.js +12 -9
- package/dist/core/palette.d.ts +48 -0
- package/dist/core/palette.js +95 -0
- package/dist/core/palette.js.map +1 -0
- package/dist/core/schema/abilities.d.ts +2 -1
- package/dist/core/schema/abilities.js +5 -1
- package/dist/core/schema/abilities.js.map +1 -1
- package/dist/core/schema/index.d.ts +11 -5
- package/dist/core/schema/index.js +13 -8
- package/dist/core/schema/index.js.map +1 -1
- package/dist/core/schema/mark-flags.d.ts +8 -1
- package/dist/core/schema/of-features.d.ts +13 -0
- package/dist/core/schema/of-features.js +14 -0
- package/dist/core/schema/of-features.js.map +1 -0
- package/dist/core/slash.d.ts +8 -6
- package/dist/core/slash.js +24 -16
- package/dist/core/slash.js.map +1 -1
- package/dist/core/surface-session.js +13 -5
- package/dist/core/surface-session.js.map +1 -1
- package/dist/core/toolbar-items.d.ts +10 -4
- package/dist/core/toolbar-items.js +269 -195
- package/dist/core/toolbar-items.js.map +1 -1
- package/dist/core/util.js +11 -0
- package/dist/core/util.js.map +1 -0
- package/dist/document/DocumentSurface.d.ts +1 -1
- package/dist/features/ai/agent-op-review.d.ts +1 -1
- package/dist/features/ai/agent-op-review.js +1 -1
- package/dist/features/ai/agent-ops.js +1 -1
- package/dist/features/ai/ai-apply.d.ts +2 -2
- package/dist/features/ai/ai-apply.js +1 -1
- package/dist/features/ai/ai-review.js +1 -1
- package/dist/features/ai/ai-sse.d.ts +6 -6
- package/dist/features/ai/ai-sse.js +20 -63
- package/dist/features/ai/ai-sse.js.map +1 -1
- package/dist/features/ai/assistant.d.ts +8 -7
- package/dist/features/ai/assistant.js +3 -3
- package/dist/features/ai/assistant.js.map +1 -1
- package/dist/features/ai/block-actions.d.ts +3 -2
- package/dist/features/ai/block-actions.js +3 -2
- package/dist/features/ai/block-actions.js.map +1 -1
- package/dist/features/ai/components/AiSelectionMenu.js +1 -1
- package/dist/features/ai/components/DocumentChatAnswer.js +1 -1
- package/dist/features/ai/components/DocumentChatOps.vue.d.ts +1 -1
- package/dist/features/ai/components/SettingsModelProfiles.js +8 -8
- package/dist/features/ai/components/SettingsModelProfiles.js.map +1 -1
- package/dist/features/ai/document-chat-model.d.ts +8 -7
- package/dist/features/ai/document-chat-model.js +5 -5
- package/dist/features/ai/document-chat-model.js.map +1 -1
- package/dist/features/ai/document-chat.js +1 -1
- package/dist/features/ai/feature.js +27 -14
- package/dist/features/ai/feature.js.map +1 -1
- package/dist/features/ai/ghost-autocomplete.d.ts +7 -6
- package/dist/features/ai/ghost-autocomplete.js +6 -9
- package/dist/features/ai/ghost-autocomplete.js.map +1 -1
- package/dist/features/ai/index.d.ts +4 -3
- package/dist/features/ai/index.js +10 -10
- package/dist/features/ai/model-profiles.d.ts +5 -4
- package/dist/features/ai/model-profiles.js +2 -2
- package/dist/features/ai/model-profiles.js.map +1 -1
- package/dist/features/ai/protocol/block-lines.js +1 -1
- package/dist/features/ai/protocol/block-lines.js.map +1 -1
- package/dist/features/ai/protocol/chat.js +4 -1
- package/dist/features/ai/protocol/chat.js.map +1 -1
- package/dist/features/ai/protocol/index.d.ts +3 -2
- package/dist/features/ai/protocol/models.d.ts +2 -16
- package/dist/features/ai/protocol/models.js.map +1 -1
- package/dist/features/ai/rate-limit.d.ts +1 -1
- package/dist/features/ai/rate-limit.js +3 -1
- package/dist/features/ai/rate-limit.js.map +1 -1
- package/dist/features/ai/react/AiSelectionMenu.js +2 -2
- package/dist/features/ai/react/AiSidebar.js +4 -4
- package/dist/features/ai/react/DocumentChatAnswer.js +1 -1
- package/dist/features/ai/react/DocumentChatOps.d.ts +1 -1
- package/dist/features/ai/react/DocumentChatOps.js +1 -1
- package/dist/features/ai/react/SettingsModelProfiles.js +8 -10
- package/dist/features/ai/react/SettingsModelProfiles.js.map +1 -1
- package/dist/features/ai/react/use-ai-assistant.d.ts +1 -1
- package/dist/features/ai/react/use-ai-assistant.js +3 -3
- package/dist/features/ai/react/use-ai-assistant.js.map +1 -1
- package/dist/features/ai/react/use-document-chat.js +2 -2
- package/dist/features/ai/react/use-document-chat.js.map +1 -1
- package/dist/features/ai/react/use-model-profiles.d.ts +2 -1
- package/dist/features/ai/selection-flow.d.ts +1 -1
- package/dist/features/ai/selection-flow.js +1 -1
- package/dist/features/ai/sidebar-flow.d.ts +1 -1
- package/dist/features/ai/sidebar-flow.js +1 -1
- package/dist/features/ai/use-ai-assistant.d.ts +1 -1
- package/dist/features/ai/use-ai-assistant.js +3 -3
- package/dist/features/ai/use-ai-assistant.js.map +1 -1
- package/dist/features/ai/use-document-chat.js +2 -2
- package/dist/features/ai/use-document-chat.js.map +1 -1
- package/dist/features/ai/use-model-profiles.d.ts +2 -1
- package/dist/features/authors/attribution.d.ts +1 -1
- package/dist/features/authors/feature.js +12 -11
- package/dist/features/authors/feature.js.map +1 -1
- package/dist/features/block-ui/block-actions.d.ts +1 -1
- package/dist/features/block-ui/block-actions.js +1 -1
- package/dist/features/block-ui/block-actions.js.map +1 -1
- package/dist/features/block-ui/components/BlockUi.js +1 -1
- package/dist/features/block-ui/feature.js +1 -0
- package/dist/features/block-ui/feature.js.map +1 -1
- package/dist/features/block-ui/react/BlockUi.js +1 -1
- package/dist/features/collab/anchor-resolver.js +1 -1
- package/dist/features/collab/feature.js +2 -0
- package/dist/features/collab/feature.js.map +1 -1
- package/dist/features/comments/components/CommentThreadView.vue.d.ts +2 -1
- package/dist/features/comments/feature.js +12 -11
- package/dist/features/comments/feature.js.map +1 -1
- package/dist/features/comments/index.d.ts +3 -2
- package/dist/features/comments/index.js +1 -1
- package/dist/features/comments/margin-layout.d.ts +3 -2
- package/dist/features/comments/model.d.ts +3 -67
- package/dist/features/comments/model.js +2 -2
- package/dist/features/comments/model.js.map +1 -1
- package/dist/features/comments/react/CommentThreadView.d.ts +3 -2
- package/dist/features/comments/react/use-comments.d.ts +2 -1
- package/dist/features/comments/react.d.ts +1 -1
- package/dist/features/comments/schema.d.ts +2 -52
- package/dist/features/comments/schema.js.map +1 -1
- package/dist/features/comments/snapshot-equality.js.map +1 -1
- package/dist/features/comments/use-comments.d.ts +3 -2
- package/dist/features/comments/vue.d.ts +1 -1
- package/dist/features/composites/accepted-children.d.ts +1 -0
- package/dist/features/composites/accepted-children.js +16 -1
- package/dist/features/composites/accepted-children.js.map +1 -1
- package/dist/features/composites/ai-brief.js +31 -0
- package/dist/features/composites/ai-brief.js.map +1 -1
- package/dist/features/composites/bibliography-command.d.ts +11 -0
- package/dist/features/composites/bibliography-form.js +90 -0
- package/dist/features/composites/bibliography-form.js.map +1 -0
- package/dist/features/composites/bibliography.d.ts +33 -0
- package/dist/features/composites/bibliography.js +120 -0
- package/dist/features/composites/bibliography.js.map +1 -0
- package/dist/features/composites/components/BibliographyEditor.js +261 -0
- package/dist/features/composites/components/BibliographyEditor.js.map +1 -0
- package/dist/features/composites/components/CompositeChrome.js +75 -26
- package/dist/features/composites/components/CompositeChrome.js.map +1 -1
- package/dist/features/composites/components/CompositeDetails.js +46 -11
- package/dist/features/composites/components/CompositeDetails.js.map +1 -1
- package/dist/features/composites/components/CompositeDetails.vue.d.ts +2 -1
- package/dist/features/composites/components/CompositeFieldEditor.js +37 -4
- package/dist/features/composites/components/CompositeFieldEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeInspector.js +17 -5
- package/dist/features/composites/components/CompositeInspector.js.map +1 -1
- package/dist/features/composites/components/CompositeTable.js +13 -4
- package/dist/features/composites/components/CompositeTable.js.map +1 -1
- package/dist/features/composites/components/CompositeTagsEditor.js +1 -1
- package/dist/features/composites/components/CompositeView.js +11 -1
- package/dist/features/composites/components/CompositeView.js.map +1 -1
- package/dist/features/composites/components/DerivationBadge.js +103 -0
- package/dist/features/composites/components/DerivationBadge.js.map +1 -0
- package/dist/features/composites/components/ReferenceFieldSelect.js +60 -0
- package/dist/features/composites/components/ReferenceFieldSelect.js.map +1 -0
- package/dist/features/composites/components/ReferenceView.js +122 -0
- package/dist/features/composites/components/ReferenceView.js.map +1 -0
- package/dist/features/composites/components/ReferenceView.vue.d.ts +96 -0
- package/dist/features/composites/components/SettingsEditingTab.js +1 -1
- package/dist/features/composites/convert.js +2 -2
- package/dist/features/composites/convert.js.map +1 -1
- package/dist/features/composites/derivation.d.ts +61 -0
- package/dist/features/composites/derivation.js +98 -0
- package/dist/features/composites/derivation.js.map +1 -0
- package/dist/features/composites/derived-chrome.js +69 -0
- package/dist/features/composites/derived-chrome.js.map +1 -0
- package/dist/features/composites/feature.js +159 -109
- package/dist/features/composites/feature.js.map +1 -1
- package/dist/features/composites/fences.d.ts +4 -3
- package/dist/features/composites/fences.js +51 -7
- package/dist/features/composites/fences.js.map +1 -1
- package/dist/features/composites/index.d.ts +12 -3
- package/dist/features/composites/index.js +15 -6
- package/dist/features/composites/inspector-model.d.ts +4 -1
- package/dist/features/composites/inspector-model.js +8 -4
- package/dist/features/composites/inspector-model.js.map +1 -1
- package/dist/features/composites/kinds.d.ts +8 -1
- package/dist/features/composites/kinds.js +145 -6
- package/dist/features/composites/kinds.js.map +1 -1
- package/dist/features/composites/legacy.d.ts +4 -1
- package/dist/features/composites/legacy.js +56 -1
- package/dist/features/composites/legacy.js.map +1 -1
- package/dist/features/composites/meta-display.js +40 -1
- package/dist/features/composites/meta-display.js.map +1 -1
- package/dist/features/composites/meta-keys.d.ts +7 -0
- package/dist/features/composites/meta-keys.js +21 -0
- package/dist/features/composites/meta-keys.js.map +1 -0
- package/dist/features/composites/node-views.d.ts +6 -3
- package/dist/features/composites/node-views.js +7 -3
- package/dist/features/composites/node-views.js.map +1 -1
- package/dist/features/composites/nodes.d.ts +6 -1
- package/dist/features/composites/nodes.js +33 -7
- package/dist/features/composites/nodes.js.map +1 -1
- package/dist/features/composites/react/BibliographyEditor.js +229 -0
- package/dist/features/composites/react/BibliographyEditor.js.map +1 -0
- package/dist/features/composites/react/CompositeChrome.js +65 -17
- package/dist/features/composites/react/CompositeChrome.js.map +1 -1
- package/dist/features/composites/react/CompositeDetails.d.ts +2 -1
- package/dist/features/composites/react/CompositeDetails.js +45 -6
- package/dist/features/composites/react/CompositeDetails.js.map +1 -1
- package/dist/features/composites/react/CompositeFieldEditor.d.ts +1 -1
- package/dist/features/composites/react/CompositeFieldEditor.js +24 -1
- package/dist/features/composites/react/CompositeFieldEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeInspector.js +11 -5
- package/dist/features/composites/react/CompositeInspector.js.map +1 -1
- package/dist/features/composites/react/CompositeStatusMenu.js +1 -1
- package/dist/features/composites/react/CompositeSummaryEditor.js +1 -1
- package/dist/features/composites/react/CompositeTable.js +16 -2
- package/dist/features/composites/react/CompositeTable.js.map +1 -1
- package/dist/features/composites/react/CompositeTagsEditor.js +2 -2
- package/dist/features/composites/react/CompositeView.js +6 -1
- package/dist/features/composites/react/CompositeView.js.map +1 -1
- package/dist/features/composites/react/DerivationBadge.js +116 -0
- package/dist/features/composites/react/DerivationBadge.js.map +1 -0
- package/dist/features/composites/react/ReferenceFieldSelect.js +52 -0
- package/dist/features/composites/react/ReferenceFieldSelect.js.map +1 -0
- package/dist/features/composites/react/ReferenceView.d.ts +11 -0
- package/dist/features/composites/react/ReferenceView.js +115 -0
- package/dist/features/composites/react/ReferenceView.js.map +1 -0
- package/dist/features/composites/react/SettingsEditingTab.js +2 -2
- package/dist/features/composites/react.d.ts +2 -1
- package/dist/features/composites/react.js +7 -3
- package/dist/features/composites/react.js.map +1 -1
- package/dist/features/composites/reference-ai.js +16 -0
- package/dist/features/composites/reference-ai.js.map +1 -0
- package/dist/features/composites/reference-label.d.ts +19 -0
- package/dist/features/composites/reference-label.js +58 -0
- package/dist/features/composites/reference-label.js.map +1 -0
- package/dist/features/composites/reference-suggestion.d.ts +10 -0
- package/dist/features/composites/reference-suggestion.js +41 -0
- package/dist/features/composites/reference-suggestion.js.map +1 -0
- package/dist/features/composites/reference-text.d.ts +18 -0
- package/dist/features/composites/reference-text.js +89 -0
- package/dist/features/composites/reference-text.js.map +1 -0
- package/dist/features/composites/reference.d.ts +44 -0
- package/dist/features/composites/reference.js +148 -0
- package/dist/features/composites/reference.js.map +1 -0
- package/dist/features/composites/reveal-source.d.ts +32 -0
- package/dist/features/composites/reveal-source.js +89 -0
- package/dist/features/composites/reveal-source.js.map +1 -0
- package/dist/features/composites/rows.d.ts +21 -2
- package/dist/features/composites/rows.js +63 -9
- package/dist/features/composites/rows.js.map +1 -1
- package/dist/features/composites/schema.d.ts +9 -3
- package/dist/features/composites/schema.js +11 -4
- package/dist/features/composites/schema.js.map +1 -1
- package/dist/features/composites/table-model.js +12 -21
- package/dist/features/composites/table-model.js.map +1 -1
- package/dist/features/composites/vue.d.ts +3 -2
- package/dist/features/composites/vue.js +8 -4
- package/dist/features/composites/vue.js.map +1 -1
- package/dist/features/media/assets.d.ts +2 -0
- package/dist/features/media/assets.js +3 -2
- package/dist/features/media/assets.js.map +1 -1
- package/dist/features/media/components/FileView.js +13 -4
- package/dist/features/media/components/FileView.js.map +1 -1
- package/dist/features/media/feature.d.ts +3 -3
- package/dist/features/media/feature.js +21 -28
- package/dist/features/media/feature.js.map +1 -1
- package/dist/features/media/file-import.js +2 -2
- package/dist/features/media/file-import.js.map +1 -1
- package/dist/features/media/index.d.ts +2 -2
- package/dist/features/media/index.js +2 -2
- package/dist/features/media/react/FileView.js +19 -2
- package/dist/features/media/react/FileView.js.map +1 -1
- package/dist/features/media/schema.d.ts +8 -0
- package/dist/features/media/schema.js +126 -11
- package/dist/features/media/schema.js.map +1 -1
- package/dist/features/media/upload.d.ts +16 -14
- package/dist/features/media/upload.js +13 -19
- package/dist/features/media/upload.js.map +1 -1
- package/dist/features/mentions/index.d.ts +4 -3
- package/dist/features/mentions/index.js +4 -1
- package/dist/features/mentions/index.js.map +1 -1
- package/dist/features/mentions/mention-text.d.ts +1 -1
- package/dist/features/mentions/mention-text.js.map +1 -1
- package/dist/features/mentions/mention.d.ts +0 -6
- package/dist/features/mentions/mention.js.map +1 -1
- package/dist/features/mentions/metadata-defaults.d.ts +2 -2
- package/dist/features/mentions/metadata-defaults.js +3 -9
- package/dist/features/mentions/metadata-defaults.js.map +1 -1
- package/dist/features/mentions/schema.d.ts +2 -1
- package/dist/features/mentions/schema.js.map +1 -1
- package/dist/features/tables/feature.d.ts +2 -1
- package/dist/features/tables/feature.js +90 -70
- package/dist/features/tables/feature.js.map +1 -1
- package/dist/features/themes/components/SettingsAppearanceTab.js +6 -9
- package/dist/features/themes/components/SettingsAppearanceTab.js.map +1 -1
- package/dist/features/themes/feature.js +2 -0
- package/dist/features/themes/feature.js.map +1 -1
- package/dist/features/themes/index.d.ts +2 -1
- package/dist/features/themes/react/SettingsAppearanceTab.js +7 -10
- package/dist/features/themes/react/SettingsAppearanceTab.js.map +1 -1
- package/dist/features/themes/schema.d.ts +2 -6
- package/dist/features/themes/schema.js.map +1 -1
- package/dist/features/themes/theme-runtime.d.ts +1 -1
- package/dist/features/themes/theme-runtime.js +4 -2
- package/dist/features/themes/theme-runtime.js.map +1 -1
- package/dist/features/transcript/TranscriptSegmentView.js +48 -28
- package/dist/features/transcript/TranscriptSegmentView.js.map +1 -1
- package/dist/features/transcript/feature.js +21 -19
- package/dist/features/transcript/feature.js.map +1 -1
- package/dist/features/transcript/react/TranscriptSegmentView.js +55 -36
- package/dist/features/transcript/react/TranscriptSegmentView.js.map +1 -1
- package/dist/features/transcript/segment-node.d.ts +2 -0
- package/dist/features/transcript/segment-node.js +35 -7
- package/dist/features/transcript/segment-node.js.map +1 -1
- package/dist/i18n/de/composites.js +91 -1
- package/dist/i18n/de/composites.js.map +1 -1
- package/dist/i18n/de/integrations.js +49 -8
- package/dist/i18n/de/integrations.js.map +1 -1
- package/dist/i18n/de/media.js +0 -1
- package/dist/i18n/de/media.js.map +1 -1
- package/dist/i18n/de/palette.js +22 -0
- package/dist/i18n/de/palette.js.map +1 -0
- package/dist/i18n/de/tables.js +0 -1
- package/dist/i18n/de/tables.js.map +1 -1
- package/dist/i18n/de/transcript.js +2 -1
- package/dist/i18n/de/transcript.js.map +1 -1
- package/dist/i18n/de/tree.js +3 -0
- package/dist/i18n/de/tree.js.map +1 -1
- package/dist/i18n/de.d.ts +157 -11
- package/dist/i18n/de.js +3 -1
- package/dist/i18n/de.js.map +1 -1
- package/dist/i18n/en/composites.js +89 -1
- package/dist/i18n/en/composites.js.map +1 -1
- package/dist/i18n/en/integrations.js +49 -8
- package/dist/i18n/en/integrations.js.map +1 -1
- package/dist/i18n/en/media.js +0 -1
- package/dist/i18n/en/media.js.map +1 -1
- package/dist/i18n/en/palette.js +22 -0
- package/dist/i18n/en/palette.js.map +1 -0
- package/dist/i18n/en/tables.js +0 -1
- package/dist/i18n/en/tables.js.map +1 -1
- package/dist/i18n/en/transcript.js +2 -1
- package/dist/i18n/en/transcript.js.map +1 -1
- package/dist/i18n/en/tree.js +3 -0
- package/dist/i18n/en/tree.js.map +1 -1
- package/dist/i18n/en.js +3 -1
- package/dist/i18n/en.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/integrations/composite-ai/bibliography-fetch.d.ts +31 -0
- package/dist/integrations/composite-ai/bibliography-fetch.js +159 -0
- package/dist/integrations/composite-ai/bibliography-fetch.js.map +1 -0
- package/dist/integrations/composite-ai/composite-fill.d.ts +30 -8
- package/dist/integrations/composite-ai/composite-fill.js +97 -56
- package/dist/integrations/composite-ai/composite-fill.js.map +1 -1
- package/dist/integrations/composite-ai/composite-summary.d.ts +4 -12
- package/dist/integrations/composite-ai/composite-summary.js +7 -26
- package/dist/integrations/composite-ai/composite-summary.js.map +1 -1
- package/dist/integrations/composite-ai/derive.d.ts +29 -0
- package/dist/integrations/composite-ai/derive.js +173 -0
- package/dist/integrations/composite-ai/derive.js.map +1 -0
- package/dist/integrations/composite-ai/index.d.ts +11 -7
- package/dist/integrations/composite-ai/index.js +72 -14
- package/dist/integrations/composite-ai/index.js.map +1 -1
- package/dist/integrations/composite-ai/rendition.d.ts +45 -0
- package/dist/integrations/composite-ai/rendition.js +314 -0
- package/dist/integrations/composite-ai/rendition.js.map +1 -0
- package/dist/integrations/composite-media/index.d.ts +7 -5
- package/dist/integrations/composite-media/index.js +86 -13
- package/dist/integrations/composite-media/index.js.map +1 -1
- package/dist/integrations/transcript-ai/index.d.ts +1 -1
- package/dist/integrations/transcript-ai/index.js +5 -2
- package/dist/integrations/transcript-ai/index.js.map +1 -1
- package/dist/integrations/transcript-ai/protocol.d.ts +2 -12
- package/dist/integrations/transcript-ai/protocol.js +0 -2
- package/dist/integrations/transcript-ai/protocol.js.map +1 -1
- package/dist/integrations/transcript-ai/transcript-cleanup.d.ts +5 -5
- package/dist/integrations/transcript-ai/transcript-cleanup.js +7 -10
- package/dist/integrations/transcript-ai/transcript-cleanup.js.map +1 -1
- package/dist/markdown/MarkdownSurface.vue.d.ts +6 -5
- package/dist/markdown/MarkdownSurface2.js +3 -6
- package/dist/markdown/MarkdownSurface2.js.map +1 -1
- package/dist/markdown/document.js +1 -1
- package/dist/markdown/source-mode.d.ts +1 -1
- package/dist/nuxt/module.d.ts +1402 -54
- package/dist/nuxt/module.js +6 -49
- package/dist/nuxt/module.js.map +1 -1
- package/dist/nuxt/runtime/install-context.d.ts +7 -3
- package/dist/nuxt/runtime/install-context.js +14 -8
- package/dist/nuxt/runtime/install-context.js.map +1 -1
- package/dist/nuxt/runtime/plugins/editor-context-nuxt-ui.client.ts +2 -2
- package/dist/nuxt/runtime/server/plugins/editor-server.js +20 -12
- package/dist/nuxt/runtime/server/plugins/editor-server.js.map +1 -1
- package/dist/presets/compose.d.ts +94 -0
- package/dist/presets/compose.js +164 -0
- package/dist/presets/compose.js.map +1 -0
- package/dist/react/AdvancedEditor.d.ts +15 -15
- package/dist/react/AdvancedEditor.js +15 -13
- package/dist/react/AdvancedEditor.js.map +1 -1
- package/dist/react/EditorCommandPalette.d.ts +13 -0
- package/dist/react/EditorCommandPalette.js +118 -0
- package/dist/react/EditorCommandPalette.js.map +1 -0
- package/dist/react/EditorSettingsModal.d.ts +5 -5
- package/dist/react/EditorSettingsModal.js +7 -4
- package/dist/react/EditorSettingsModal.js.map +1 -1
- package/dist/react/EditorSettingsPanel.d.ts +7 -7
- package/dist/react/EditorSettingsPanel.js +8 -5
- package/dist/react/EditorSettingsPanel.js.map +1 -1
- package/dist/react/EditorSurface.d.ts +7 -7
- package/dist/react/EditorSurface.js +10 -6
- package/dist/react/EditorSurface.js.map +1 -1
- package/dist/react/EditorToolbar.d.ts +4 -6
- package/dist/react/EditorToolbar.js +29 -37
- package/dist/react/EditorToolbar.js.map +1 -1
- package/dist/react/SimpleEditor.d.ts +22 -23
- package/dist/react/SimpleEditor.js +21 -7
- package/dist/react/SimpleEditor.js.map +1 -1
- package/dist/react/advanced.d.ts +4 -3
- package/dist/react/advanced.js +2 -2
- package/dist/react/compose.d.ts +20 -0
- package/dist/react/compose.js +49 -0
- package/dist/react/compose.js.map +1 -0
- package/dist/react/composed-surface.d.ts +39 -0
- package/dist/react/composed-surface.js +71 -0
- package/dist/react/composed-surface.js.map +1 -0
- package/dist/react/context.js +6 -2
- package/dist/react/context.js.map +1 -1
- package/dist/react/index.d.ts +2 -1
- package/dist/react/index.js +2 -1
- package/dist/react/key-labels.js +15 -0
- package/dist/react/key-labels.js.map +1 -0
- package/dist/react/settings.d.ts +1 -1
- package/dist/react/simple.d.ts +2 -2
- package/dist/react/ui/command.js +36 -1
- package/dist/react/ui/command.js.map +1 -1
- package/dist/schema/advanced.d.ts +6 -6
- package/dist/schema/advanced.js +26 -29
- package/dist/schema/advanced.js.map +1 -1
- package/dist/server/ai.d.ts +5 -16
- package/dist/server/ai.js.map +1 -1
- package/dist/server/auth.d.ts +9 -0
- package/dist/server/collab-state.d.ts +1 -1
- package/dist/server/collab-state.js.map +1 -1
- package/dist/server/collab.d.ts +13 -13
- package/dist/server/collab.js +34 -18
- package/dist/server/collab.js.map +1 -1
- package/dist/server/crossref.js +78 -0
- package/dist/server/crossref.js.map +1 -0
- package/dist/server/errors.d.ts +1 -1
- package/dist/server/errors.js +1 -1
- package/dist/server/errors.js.map +1 -1
- package/dist/server/extract.js +308 -0
- package/dist/server/extract.js.map +1 -0
- package/dist/{nuxt/runtime/server/utils/editor-route.js → server/h3.js} +8 -16
- package/dist/server/h3.js.map +1 -0
- package/dist/server/handlers/ai.d.ts +30 -9
- package/dist/server/handlers/ai.js +170 -36
- package/dist/server/handlers/ai.js.map +1 -1
- package/dist/server/handlers/context.d.ts +12 -5
- package/dist/server/handlers/context.js +10 -4
- package/dist/server/handlers/context.js.map +1 -1
- package/dist/server/handlers/editor.d.ts +19 -13
- package/dist/server/handlers/editor.js +49 -38
- package/dist/server/handlers/editor.js.map +1 -1
- package/dist/server/handlers/index.d.ts +4 -4
- package/dist/server/handlers/index.js +4 -4
- package/dist/server/host.d.ts +16 -25
- package/dist/server/host.js +58 -41
- package/dist/server/host.js.map +1 -1
- package/dist/server/index.d.ts +6 -4
- package/dist/server/index.js +3 -2
- package/dist/server/pdf.js +97 -0
- package/dist/server/pdf.js.map +1 -0
- package/dist/server/{adapter.d.ts → ports.d.ts} +81 -30
- package/dist/server/ports.js +29 -0
- package/dist/server/ports.js.map +1 -0
- package/dist/server/routes.js +144 -0
- package/dist/server/routes.js.map +1 -0
- package/dist/settings/index.d.ts +1 -1
- package/dist/settings/index.js.map +1 -1
- package/dist/styles/composites.css +25 -0
- package/dist/tree/DocumentTree.js +56 -29
- package/dist/tree/DocumentTree.js.map +1 -1
- package/dist/tree/react/DocumentTree.js +23 -0
- package/dist/tree/react/DocumentTree.js.map +1 -1
- package/dist/tree/tree-host.js +2 -2
- package/dist/tree/tree-items.js +1 -1
- package/dist/vue/AdvancedEditor.js +30 -9
- package/dist/vue/AdvancedEditor.js.map +1 -1
- package/dist/vue/AdvancedEditor.vue.d.ts +28 -8
- package/dist/vue/SimpleEditor.js +62 -16
- package/dist/vue/SimpleEditor.js.map +1 -1
- package/dist/vue/SimpleEditor.vue.d.ts +37 -7
- package/dist/vue/advanced.d.ts +3 -2
- package/dist/vue/advanced.js +2 -2
- package/dist/vue/components/EditorCommandPalette.js +91 -0
- package/dist/vue/components/EditorCommandPalette.js.map +1 -0
- package/dist/vue/components/EditorCommandPalette.vue.d.ts +15 -0
- package/dist/vue/components/EditorSettingsModal.js +10 -6
- package/dist/vue/components/EditorSettingsModal.js.map +1 -1
- package/dist/vue/components/EditorSettingsModal.vue.d.ts +4 -4
- package/dist/vue/components/EditorSettingsPanel.js +10 -6
- package/dist/vue/components/EditorSettingsPanel.js.map +1 -1
- package/dist/vue/components/EditorSettingsPanel.vue.d.ts +6 -6
- package/dist/vue/components/EditorSurface.js +11 -6
- package/dist/vue/components/EditorSurface.js.map +1 -1
- package/dist/vue/components/EditorSurface.vue.d.ts +7 -7
- package/dist/vue/components/EditorToolbar.js +41 -49
- package/dist/vue/components/EditorToolbar.js.map +1 -1
- package/dist/vue/components/EditorToolbar.vue.d.ts +2 -4
- package/dist/vue/compose.d.ts +17 -0
- package/dist/vue/compose.js +51 -0
- package/dist/vue/compose.js.map +1 -0
- package/dist/vue/context-key.d.ts +6 -0
- package/dist/vue/context-key.js +6 -0
- package/dist/vue/context-key.js.map +1 -0
- package/dist/vue/context.d.ts +8 -6
- package/dist/vue/context.js +6 -5
- package/dist/vue/context.js.map +1 -1
- package/dist/vue/index.d.ts +10 -8
- package/dist/vue/index.js +10 -8
- package/dist/vue/kit/index.d.ts +2 -2
- package/dist/vue/kit/nuxt-ui.js +23 -0
- package/dist/vue/kit/nuxt-ui.js.map +1 -1
- package/dist/vue/kit/types.d.ts +40 -1
- package/package.json +30 -16
- package/dist/adapters/comments/client.d.ts +0 -64
- package/dist/adapters/comments/client.js.map +0 -1
- package/dist/adapters/routes.js.map +0 -1
- package/dist/core/toolbar.d.ts +0 -74
- package/dist/core/toolbar.js +0 -45
- package/dist/core/toolbar.js.map +0 -1
- package/dist/integrations/composite-ai/document-transcribe.d.ts +0 -14
- package/dist/integrations/composite-ai/document-transcribe.js +0 -89
- package/dist/integrations/composite-ai/document-transcribe.js.map +0 -1
- package/dist/nuxt/runtime/server/api/ai/chat.post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/ai/chat.post.js +0 -8
- package/dist/nuxt/runtime/server/api/ai/chat.post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/ai/complete.post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/ai/complete.post.js +0 -8
- package/dist/nuxt/runtime/server/api/ai/complete.post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/ai/generate.post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/ai/generate.post.js +0 -8
- package/dist/nuxt/runtime/server/api/ai/generate.post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/ai/models.get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/ai/models.get.js +0 -8
- package/dist/nuxt/runtime/server/api/ai/models.get.js.map +0 -1
- package/dist/nuxt/runtime/server/api/ai/transcribe.post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/ai/transcribe.post.js +0 -8
- package/dist/nuxt/runtime/server/api/ai/transcribe.post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.js +0 -8
- package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/assets/[id].post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/assets/[id].post.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/assets/[id].post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/settings.get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/settings.get.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/settings.get.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/settings.put.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/settings.put.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/settings.put.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/tags.get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/tags.get.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/tags.get.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/themes/[id].get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/themes/[id].get.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/themes/[id].get.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/themes/index.get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/themes/index.get.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/themes/index.get.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/themes/index.post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/themes/index.post.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/themes/index.post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/users.get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/users.get.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/users.get.js.map +0 -1
- package/dist/nuxt/runtime/server/plugins/collab.d.ts +0 -5
- package/dist/nuxt/runtime/server/plugins/collab.js +0 -10
- package/dist/nuxt/runtime/server/plugins/collab.js.map +0 -1
- package/dist/nuxt/runtime/server/routes/collab/[id].d.ts +0 -5
- package/dist/nuxt/runtime/server/routes/collab/[id].js +0 -35
- package/dist/nuxt/runtime/server/routes/collab/[id].js.map +0 -1
- package/dist/nuxt/runtime/server/utils/editor-route.d.ts +0 -11
- package/dist/nuxt/runtime/server/utils/editor-route.js.map +0 -1
- package/dist/presets/advanced.d.ts +0 -33
- package/dist/presets/advanced.js +0 -50
- package/dist/presets/advanced.js.map +0 -1
- package/dist/presets/simple.d.ts +0 -9
- package/dist/presets/simple.js +0 -12
- package/dist/presets/simple.js.map +0 -1
- package/dist/react/advanced-preset.d.ts +0 -11
- package/dist/react/advanced-preset.js +0 -31
- package/dist/react/advanced-preset.js.map +0 -1
- package/dist/vue/advanced-preset.d.ts +0 -13
- package/dist/vue/advanced-preset.js +0 -33
- package/dist/vue/advanced-preset.js.map +0 -1
- package/docs/extending.md +0 -538
- package/docs/integration.md +0 -632
- package/docs/llms.md +0 -383
- package/docs/usage.md +0 -1076
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/integrations/composite-ai/index.ts"],"sourcesContent":["import type { BlockAction, EditorFeature, FeatureContext } from '../../core'\nimport { ABILITY } from '../../core/schema'\nimport { modelProfiles, withHeading } from '../../features/ai'\nimport { structureOf } from '../../features/composites'\nimport { compositeFence, compositeKind, compositeKindsOf } from '../../features/composites/schema'\nimport { fillComposite } from './composite-fill'\nimport {
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/integrations/composite-ai/index.ts"],"sourcesContent":["import { type AnyExtension, Extension } from '@tiptap/core'\nimport type { BlockAction, EditorFeature, FeatureContext } from '../../core'\nimport { ABILITY } from '../../core/schema'\nimport { modelProfiles, withHeading } from '../../features/ai'\nimport { structureOf } from '../../features/composites'\nimport '../../features/composites/bibliography-command'\nimport { compositeFence, compositeKind, compositeKindsOf } from '../../features/composites/schema'\nimport { fillComposite } from './composite-fill'\nimport { canDeriveAfter, derivableKindsOf, deriveComposite, isDerivableSource } from './derive'\nimport { canFetchBibliography, fetchBibliography } from './bibliography-fetch'\nimport { compositeSourceText, summarizeComposite } from './composite-summary'\nimport { canCreateRendition, canRegenerateRendition, createRendition, regenerateRendition } from './rendition'\n\nexport { type CompositeBodyResult, fillComposite, generateCompositeBody } from './composite-fill'\nexport { COMPOSITE_BODY_START, compositeSourceText, summarizeComposite } from './composite-summary'\nexport { canCreateRendition, canRegenerateRendition, createRendition, regenerateRendition, type RenditionOptions } from './rendition'\nexport { canDeriveAfter, derivableKindsOf, deriveComposite, isDerivableSource } from './derive'\nexport { canFetchBibliography, doiOf, fetchBibliography } from './bibliography-fetch'\n\n/** The editor command `fetchCompositeBibliography` (declared by composites) behind the bibliography editor's „DOI abrufen“ button; absent without the AI capability. */\nfunction bibliographyFetchExtensions(ctx: FeatureContext): AnyExtension[] {\n const ai = ctx.backend.ai\n if (!ai) return []\n return [Extension.create({\n name: 'compositeBibliographyFetch',\n addCommands: () => ({\n fetchCompositeBibliography: (pos: number) => ({ editor }) => {\n void fetchBibliography(editor, pos, ai, modelProfiles(ctx.app).modelRef, ctx.notify, ctx.t, ctx.documentId)\n return true\n },\n }),\n })]\n}\n\nfunction compositeAiActions(ctx: FeatureContext): BlockAction[] {\n const ai = ctx.backend.ai\n // Without the AI capability there is nothing to run (`composeEditor` omits the integration in that case).\n if (!ai) return []\n return [\n {\n id: 'composite-fill',\n label: ctx.t('integrations.compositeFill.action'),\n icon: 'i-lucide-wand-sparkles',\n ability: ABILITY.aiGenerate,\n order: 25,\n isVisible: ({ editor, node }) => node.type.name === 'composite' && compositeKind(compositeKindsOf(editor), String(node.attrs.kind)).ai !== undefined,\n run: ({ editor, pos }) => {\n void fillComposite(editor, pos, ai, modelProfiles(ctx.app).modelRef, ctx.notify, ctx.t)\n },\n },\n {\n id: 'composite-summarize',\n label: ctx.t('integrations.compositeSummary.action'),\n icon: 'i-lucide-text-quote',\n ability: ABILITY.compositeSummarize,\n order: 30,\n isVisible: ({ node }) => compositeSourceText(node).trim().length > 0,\n run: ({ editor, pos }) => {\n void summarizeComposite(editor, pos, ai, modelProfiles(ctx.app).modelRef, ctx.notify, ctx.t)\n },\n },\n {\n id: 'composite-derive',\n label: ctx.t('integrations.compositeDerive.action'),\n icon: 'i-lucide-git-branch',\n ability: ABILITY.compositeDerive,\n order: 452,\n isVisible: ({ editor, node }) => isDerivableSource(editor, node),\n menu: ({ editor, pos }) => derivableKindsOf(editor).map(kind => ({\n label: kind.label,\n icon: kind.icon,\n disabled: !canDeriveAfter(editor, pos, kind.id),\n onSelect: () => {\n void deriveComposite(editor, pos, kind.id, ai, modelProfiles(ctx.app).modelRef, ctx.notify, ctx.t)\n },\n })),\n },\n {\n id: 'bibliography-fetch',\n label: ctx.t('integrations.bibliographyFetch.action'),\n icon: 'i-lucide-book-marked',\n ability: ABILITY.compositeDerive,\n order: 453,\n isVisible: ({ editor, node }) => canFetchBibliography(editor, node),\n run: ({ editor, pos }) => {\n void fetchBibliography(editor, pos, ai, modelProfiles(ctx.app).modelRef, ctx.notify, ctx.t, ctx.documentId)\n },\n },\n {\n id: 'rendition-create',\n label: ctx.t('integrations.rendition.action'),\n icon: 'i-lucide-captions',\n ability: ABILITY.compositeDerive,\n order: 450,\n isVisible: ({ editor, node }) => canCreateRendition(editor, node, !!ctx.ai?.transcription),\n run: ({ editor, pos }) => {\n void createRendition(editor, pos, ai, modelProfiles(ctx.app).modelRef, ctx.notify, ctx.t)\n },\n },\n {\n id: 'rendition-regenerate',\n label: ctx.t('integrations.rendition.regenerate'),\n icon: 'i-lucide-refresh-cw',\n ability: ABILITY.compositeDerive,\n order: 451,\n isVisible: ({ editor, node, pos }) => canRegenerateRendition(editor, node, pos, !!ctx.ai?.transcription),\n run: ({ editor, pos }) => {\n regenerateRendition(editor, pos, ai, modelProfiles(ctx.app).modelRef, ctx.notify, ctx.t)\n },\n },\n ]\n}\n\n/**\n * AI on composites (requires `composites`, `ai`, `media`): the „Baustein füllen (KI)“ block action (on composites of\n * kinds with an `ai` configuration: brief + document → task `fill-block`, the result opens the diff review over the\n * body), the „Zusammenfassung erzeugen“ block action (streams a\n * summary of a composite's body into its description), the „Lesefassung erzeugen“ / „Neu erzeugen (ersetzen)“\n * actions of source-holding Bausteine (`ai.extract`: a rendition child with the transcript, full text or description of\n * the source; a recording needs the app's public AI configuration to enable transcription),\n * and the composite-structure form of AI results: with `composite` structure an AI result that\n * has a heading is inserted as a `section` composite fence, otherwise (and in flat structure) the base AI heading\n * is used. It is the preset's single `formatAiResult` contributor. The base AI feature and the composites feature do\n * not know it. Framework-free: notices go through the surface's `ctx.notify`, the model through the app's\n * `modelProfiles(ctx.app)`.\n */\nexport function compositeAiFeature(): EditorFeature<never> {\n return {\n id: 'composite-ai',\n dimension: 'ai',\n requires: ['composites', 'ai', 'media'],\n blockActions: compositeAiActions,\n extensions: bibliographyFetchExtensions,\n formatAiResult: (editor, markdown, heading) => {\n if (!heading) return markdown\n const text = withHeading(heading, markdown)\n return structureOf(editor) === 'composite' ? compositeFence('section', {}, text) : text\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAoBA,SAAS,4BAA4B,KAAqC;CACxE,MAAM,KAAK,IAAI,QAAQ;CACvB,IAAI,CAAC,IAAI,OAAO,CAAC;CACjB,OAAO,CAAC,UAAU,OAAO;EACvB,MAAM;EACN,oBAAoB,EAClB,6BAA6B,SAAiB,EAAE,aAAa;GAC3D,kBAAuB,QAAQ,KAAK,IAAI,cAAc,IAAI,GAAG,CAAC,CAAC,UAAU,IAAI,QAAQ,IAAI,GAAG,IAAI,UAAU;GAC1G,OAAO;EACT,EACF;CACF,CAAC,CAAC;AACJ;AAEA,SAAS,mBAAmB,KAAoC;CAC9D,MAAM,KAAK,IAAI,QAAQ;CAEvB,IAAI,CAAC,IAAI,OAAO,CAAC;CACjB,OAAO;EACL;GACE,IAAI;GACJ,OAAO,IAAI,EAAE,mCAAmC;GAChD,MAAM;GACN,SAAS,QAAQ;GACjB,OAAO;GACP,YAAY,EAAE,QAAQ,WAAW,KAAK,KAAK,SAAS,eAAe,cAAc,iBAAiB,MAAM,GAAG,OAAO,KAAK,MAAM,IAAI,CAAC,CAAC,CAAC,OAAO,KAAA;GAC3I,MAAM,EAAE,QAAQ,UAAU;IACxB,cAAmB,QAAQ,KAAK,IAAI,cAAc,IAAI,GAAG,CAAC,CAAC,UAAU,IAAI,QAAQ,IAAI,CAAC;GACxF;EACF;EACA;GACE,IAAI;GACJ,OAAO,IAAI,EAAE,sCAAsC;GACnD,MAAM;GACN,SAAS,QAAQ;GACjB,OAAO;GACP,YAAY,EAAE,WAAW,oBAAoB,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS;GACnE,MAAM,EAAE,QAAQ,UAAU;IACxB,mBAAwB,QAAQ,KAAK,IAAI,cAAc,IAAI,GAAG,CAAC,CAAC,UAAU,IAAI,QAAQ,IAAI,CAAC;GAC7F;EACF;EACA;GACE,IAAI;GACJ,OAAO,IAAI,EAAE,qCAAqC;GAClD,MAAM;GACN,SAAS,QAAQ;GACjB,OAAO;GACP,YAAY,EAAE,QAAQ,WAAW,kBAAkB,QAAQ,IAAI;GAC/D,OAAO,EAAE,QAAQ,UAAU,iBAAiB,MAAM,CAAC,CAAC,KAAI,UAAS;IAC/D,OAAO,KAAK;IACZ,MAAM,KAAK;IACX,UAAU,CAAC,eAAe,QAAQ,KAAK,KAAK,EAAE;IAC9C,gBAAgB;KACd,gBAAqB,QAAQ,KAAK,KAAK,IAAI,IAAI,cAAc,IAAI,GAAG,CAAC,CAAC,UAAU,IAAI,QAAQ,IAAI,CAAC;IACnG;GACF,EAAE;EACJ;EACA;GACE,IAAI;GACJ,OAAO,IAAI,EAAE,uCAAuC;GACpD,MAAM;GACN,SAAS,QAAQ;GACjB,OAAO;GACP,YAAY,EAAE,QAAQ,WAAW,qBAAqB,QAAQ,IAAI;GAClE,MAAM,EAAE,QAAQ,UAAU;IACxB,kBAAuB,QAAQ,KAAK,IAAI,cAAc,IAAI,GAAG,CAAC,CAAC,UAAU,IAAI,QAAQ,IAAI,GAAG,IAAI,UAAU;GAC5G;EACF;EACA;GACE,IAAI;GACJ,OAAO,IAAI,EAAE,+BAA+B;GAC5C,MAAM;GACN,SAAS,QAAQ;GACjB,OAAO;GACP,YAAY,EAAE,QAAQ,WAAW,mBAAmB,QAAQ,MAAM,CAAC,CAAC,IAAI,IAAI,aAAa;GACzF,MAAM,EAAE,QAAQ,UAAU;IACxB,gBAAqB,QAAQ,KAAK,IAAI,cAAc,IAAI,GAAG,CAAC,CAAC,UAAU,IAAI,QAAQ,IAAI,CAAC;GAC1F;EACF;EACA;GACE,IAAI;GACJ,OAAO,IAAI,EAAE,mCAAmC;GAChD,MAAM;GACN,SAAS,QAAQ;GACjB,OAAO;GACP,YAAY,EAAE,QAAQ,MAAM,UAAU,uBAAuB,QAAQ,MAAM,KAAK,CAAC,CAAC,IAAI,IAAI,aAAa;GACvG,MAAM,EAAE,QAAQ,UAAU;IACxB,oBAAoB,QAAQ,KAAK,IAAI,cAAc,IAAI,GAAG,CAAC,CAAC,UAAU,IAAI,QAAQ,IAAI,CAAC;GACzF;EACF;CACF;AACF;;;;;;;;;;;;;;AAeA,SAAgB,qBAA2C;CACzD,OAAO;EACL,IAAI;EACJ,WAAW;EACX,UAAU;GAAC;GAAc;GAAM;EAAO;EACtC,cAAc;EACd,YAAY;EACZ,iBAAiB,QAAQ,UAAU,YAAY;GAC7C,IAAI,CAAC,SAAS,OAAO;GACrB,MAAM,OAAO,YAAY,SAAS,QAAQ;GAC1C,OAAO,YAAY,MAAM,MAAM,cAAc,eAAe,WAAW,CAAC,GAAG,IAAI,IAAI;EACrF;CACF;AACF"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Translate } from "../../i18n/index.js";
|
|
2
|
+
import { EditorBackend } from "../../core/backend.js";
|
|
3
|
+
import { Notifier } from "../../core/notify.js";
|
|
4
|
+
import { ModelRef } from "../../core/backend-types.js";
|
|
5
|
+
import "../../features/ai/index.js";
|
|
6
|
+
import { Editor } from "@tiptap/core";
|
|
7
|
+
import { Node as Node$1 } from "@tiptap/pm/model";
|
|
8
|
+
//#region src/integrations/composite-ai/rendition.d.ts
|
|
9
|
+
export interface RenditionOptions {
|
|
10
|
+
/**
|
|
11
|
+
* Replace the rendition at this position (a child of the source-holding Baustein) in place instead of adding a new one
|
|
12
|
+
* after the source: its chrome (title, description, tags) and block id stay, body and derivation are new.
|
|
13
|
+
*/
|
|
14
|
+
replace?: {
|
|
15
|
+
pos: number;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* „Lesefassung erzeugen“: extracts the readable content of the source of the Baustein at `pos` (`ai.extract`, method
|
|
20
|
+
* `auto`: transcript with timestamps for audio/video, full text or OCR for a PDF, a description for an image) and adds
|
|
21
|
+
* it as a `rendition` Baustein right after the source block, carrying `meta.derivation` (asset, method, model, hashes,
|
|
22
|
+
* the stored raw output). Bibliographic data the server found fills an empty `meta.bib` of the Baustein, and the work's
|
|
23
|
+
* title an empty Baustein title. With `options.replace` the existing rendition is replaced in place (same block id).
|
|
24
|
+
* The Baustein is anchored through its description when the request starts and found again after it ends, so edits
|
|
25
|
+
* while it runs do not misplace the result. Notices go through `notify`, in the language of `t`; the progress notice
|
|
26
|
+
* stays until the request ends.
|
|
27
|
+
*/
|
|
28
|
+
export declare function createRendition(editor: Editor, pos: number, ai: NonNullable<EditorBackend['ai']>, modelRef: (slot: 'generate') => ModelRef, notify: Notifier, t: Translate, options?: RenditionOptions): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Whether „Lesefassung erzeugen“ applies to `node`: a Baustein of a source-holding kind whose source block was
|
|
31
|
+
* found. A recording needs speech-to-text (`transcription`: the app's public configuration enables it); everything else
|
|
32
|
+
* is extracted by the server.
|
|
33
|
+
*/
|
|
34
|
+
export declare function canCreateRendition(editor: Editor, node: Node$1, transcription: boolean): boolean;
|
|
35
|
+
/** Whether „Neu erzeugen (ersetzen)“ applies to the Baustein `node` at `pos`: an asset-derived rendition inside a Baustein that still has a source. */
|
|
36
|
+
export declare function canRegenerateRendition(editor: Editor, node: Node$1, pos: number, transcription: boolean): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* „Neu erzeugen (ersetzen)“: makes the rendition at `pos` again from the source of its Baustein and replaces it in place
|
|
39
|
+
* (`createRendition` with `replace`; the block id stays, so references keep resolving). A rendition whose body was
|
|
40
|
+
* edited since it was made is not replaced silently: a warning notice offers „Trotzdem ersetzen“, dismissing the notice
|
|
41
|
+
* cancels. The rendition is found again by its id when the button is pressed.
|
|
42
|
+
*/
|
|
43
|
+
export declare function regenerateRendition(editor: Editor, pos: number, ai: NonNullable<EditorBackend['ai']>, modelRef: (slot: 'generate') => ModelRef, notify: Notifier, t: Translate): void;
|
|
44
|
+
//#endregion
|
|
45
|
+
//# sourceMappingURL=rendition.d.ts.map
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { parseBlocks, structureBlocks } from "../../core/pipeline.js";
|
|
2
|
+
import { blockIdOf, findBlockById, newBlockId } from "../../core/schema/block-ids.js";
|
|
3
|
+
import { captureRange, releaseRanges, resolveRange } from "../../core/doc-anchors.js";
|
|
4
|
+
import { fetchErrorMessage } from "../../core/fetch-error.js";
|
|
5
|
+
import { sha256Hex } from "../../core/hash.js";
|
|
6
|
+
import { compositeKind, kindAccepts } from "../../features/composites/kinds.js";
|
|
7
|
+
import { DERIVATION_KEY } from "../../features/composites/meta-keys.js";
|
|
8
|
+
import { bodyMarkdown, derivationOf, derivationState, sourceOf } from "../../features/composites/derivation.js";
|
|
9
|
+
import { compositeJSON, compositeKindsOf } from "../../features/composites/nodes.js";
|
|
10
|
+
import { bibOf } from "../../features/composites/bibliography.js";
|
|
11
|
+
import { isRateLimited, notifyAiRateLimited } from "../../features/ai/rate-limit.js";
|
|
12
|
+
import { Fragment } from "@tiptap/pm/model";
|
|
13
|
+
//#region src/integrations/composite-ai/rendition.ts
|
|
14
|
+
/** Methods with their own title of a fresh rendition (`integrations.rendition.title.<method>`). */
|
|
15
|
+
const TITLED_METHODS = [
|
|
16
|
+
"transcription",
|
|
17
|
+
"pdf-text",
|
|
18
|
+
"ocr",
|
|
19
|
+
"description"
|
|
20
|
+
];
|
|
21
|
+
/** What the server's `warnings` codes say; an unknown code is shown as it is. */
|
|
22
|
+
const WARNING_KEYS = {
|
|
23
|
+
"ocr-unavailable": "integrations.rendition.warning.ocr-unavailable",
|
|
24
|
+
"crossref-unavailable": "integrations.rendition.warning.crossref-unavailable",
|
|
25
|
+
"pages-truncated": "integrations.rendition.warning.pages-truncated",
|
|
26
|
+
"ocr-truncated": "integrations.rendition.warning.ocr-truncated",
|
|
27
|
+
"bibliography-failed": "integrations.rendition.warning.bibliography-failed"
|
|
28
|
+
};
|
|
29
|
+
/** The `<!-- page N -->` line the server puts at the start of every PDF page after the first (`joinPages`). */
|
|
30
|
+
const PAGE_MARKER = /^<!-- page (\d+) -->[ \t]*$/gm;
|
|
31
|
+
/**
|
|
32
|
+
* `markdown` with every page marker line replaced by an emphasised page label paragraph (`*S. 2*`): parsed as it is, a
|
|
33
|
+
* marker is an HTML comment and would leave an empty paragraph without the page. The stored raw output keeps the markers.
|
|
34
|
+
*/
|
|
35
|
+
function withPageLabels(markdown, t) {
|
|
36
|
+
return markdown.replace(PAGE_MARKER, (_marker, page) => `*${t("integrations.rendition.page", { n: page })}*`);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The body blocks of a rendition: one `transcriptSegment` per timed segment (speaker empty, `start`/`end` in seconds)
|
|
40
|
+
* when the editor has the transcript feature, else the Markdown parsed and brought into the preferred structure
|
|
41
|
+
* (chapters become nested `section` Bausteine in composite structure; PDF page breaks become page label paragraphs).
|
|
42
|
+
*/
|
|
43
|
+
function renditionBody(editor, response, t) {
|
|
44
|
+
if (editor.schema.nodes.transcriptSegment && response.segments?.length) {
|
|
45
|
+
const segments = response.segments.filter((segment) => segment.text.trim()).map((segment) => ({
|
|
46
|
+
type: "transcriptSegment",
|
|
47
|
+
attrs: {
|
|
48
|
+
speaker: "",
|
|
49
|
+
start: segment.start,
|
|
50
|
+
end: segment.end
|
|
51
|
+
},
|
|
52
|
+
content: [{
|
|
53
|
+
type: "text",
|
|
54
|
+
text: segment.text.trim()
|
|
55
|
+
}]
|
|
56
|
+
}));
|
|
57
|
+
if (segments.length) return segments;
|
|
58
|
+
}
|
|
59
|
+
return response.markdown.trim() ? structureBlocks(editor, parseBlocks(editor, withPageLabels(response.markdown, t)).blocks) : [];
|
|
60
|
+
}
|
|
61
|
+
/** `node` with `derivation` in its meta, `outputHash` being the hash of the Markdown of its body (what `derivationState` compares later). */
|
|
62
|
+
function sealed(editor, node, derivation) {
|
|
63
|
+
const outputHash = sha256Hex(bodyMarkdown(editor, node));
|
|
64
|
+
return node.type.create({
|
|
65
|
+
...node.attrs,
|
|
66
|
+
meta: {
|
|
67
|
+
...node.attrs.meta,
|
|
68
|
+
[DERIVATION_KEY]: {
|
|
69
|
+
...derivation,
|
|
70
|
+
outputHash
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}, node.content, node.marks);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* „Lesefassung erzeugen“: extracts the readable content of the source of the Baustein at `pos` (`ai.extract`, method
|
|
77
|
+
* `auto`: transcript with timestamps for audio/video, full text or OCR for a PDF, a description for an image) and adds
|
|
78
|
+
* it as a `rendition` Baustein right after the source block, carrying `meta.derivation` (asset, method, model, hashes,
|
|
79
|
+
* the stored raw output). Bibliographic data the server found fills an empty `meta.bib` of the Baustein, and the work's
|
|
80
|
+
* title an empty Baustein title. With `options.replace` the existing rendition is replaced in place (same block id).
|
|
81
|
+
* The Baustein is anchored through its description when the request starts and found again after it ends, so edits
|
|
82
|
+
* while it runs do not misplace the result. Notices go through `notify`, in the language of `t`; the progress notice
|
|
83
|
+
* stays until the request ends.
|
|
84
|
+
*/
|
|
85
|
+
async function createRendition(editor, pos, ai, modelRef, notify, t, options = {}) {
|
|
86
|
+
const kinds = compositeKindsOf(editor);
|
|
87
|
+
const composite = editor.state.doc.nodeAt(pos);
|
|
88
|
+
const source = composite && sourceOf(composite, kinds);
|
|
89
|
+
if (composite?.type.name !== "composite" || !source) return;
|
|
90
|
+
const asset = source.asset;
|
|
91
|
+
if (!asset) {
|
|
92
|
+
notify({
|
|
93
|
+
title: t("integrations.rendition.noSource"),
|
|
94
|
+
kind: "error"
|
|
95
|
+
});
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (!kindAccepts(kinds, String(composite.attrs.kind), "rendition")) {
|
|
99
|
+
notify({
|
|
100
|
+
title: t("integrations.rendition.notAccepted"),
|
|
101
|
+
kind: "error"
|
|
102
|
+
});
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
let replaceId = null;
|
|
106
|
+
if (options.replace) {
|
|
107
|
+
const target = editor.state.doc.nodeAt(options.replace.pos);
|
|
108
|
+
replaceId = target && options.replace.pos > pos && options.replace.pos < pos + composite.nodeSize ? blockIdOf(target) : null;
|
|
109
|
+
if (target?.type.name !== "composite" || !replaceId) return;
|
|
110
|
+
}
|
|
111
|
+
const descriptionPos = pos + 1 + composite.child(0).nodeSize;
|
|
112
|
+
const anchor = captureRange(editor, {
|
|
113
|
+
from: descriptionPos + 1,
|
|
114
|
+
to: descriptionPos + 1 + composite.child(1).content.size
|
|
115
|
+
});
|
|
116
|
+
const toastId = `rendition-${blockIdOf(composite) ?? asset.name}`;
|
|
117
|
+
const wantsBibliography = compositeKind(kinds, String(composite.attrs.kind)).fields.some((field) => field.type === "bibliography");
|
|
118
|
+
const model = modelRef("generate");
|
|
119
|
+
const controller = new AbortController();
|
|
120
|
+
const abort = () => controller.abort();
|
|
121
|
+
editor.on("destroy", abort);
|
|
122
|
+
notify({
|
|
123
|
+
id: toastId,
|
|
124
|
+
title: t("integrations.rendition.running"),
|
|
125
|
+
kind: "info",
|
|
126
|
+
icon: "i-lucide-loader-circle",
|
|
127
|
+
duration: 0
|
|
128
|
+
});
|
|
129
|
+
try {
|
|
130
|
+
const response = await ai.extract({
|
|
131
|
+
documentId: asset.documentId,
|
|
132
|
+
name: asset.name,
|
|
133
|
+
method: "auto",
|
|
134
|
+
model,
|
|
135
|
+
bibliography: wantsBibliography
|
|
136
|
+
}, controller.signal);
|
|
137
|
+
if (editor.isDestroyed) return;
|
|
138
|
+
const body = renditionBody(editor, response, t);
|
|
139
|
+
if (!body.length) {
|
|
140
|
+
notify({
|
|
141
|
+
title: t("integrations.rendition.empty.title"),
|
|
142
|
+
description: t("integrations.rendition.empty.description"),
|
|
143
|
+
kind: "error"
|
|
144
|
+
});
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const range = resolveRange(editor.state, anchor);
|
|
148
|
+
const $from = range && editor.state.doc.resolve(range.from);
|
|
149
|
+
const parentPos = $from && $from.parent.type.name === "compositeDescription" ? $from.before($from.depth - 1) : null;
|
|
150
|
+
const parent = parentPos === null ? null : editor.state.doc.nodeAt(parentPos);
|
|
151
|
+
const currentSource = parent && sourceOf(parent, kinds);
|
|
152
|
+
const replaced = replaceId ? findBlockById(editor.state.doc, replaceId) : null;
|
|
153
|
+
if (parentPos === null || !parent || !currentSource || replaceId !== null && (!replaced || replaced.pos <= parentPos || replaced.pos >= parentPos + parent.nodeSize)) {
|
|
154
|
+
notify({
|
|
155
|
+
title: t("integrations.rendition.gone.title"),
|
|
156
|
+
description: t("integrations.rendition.gone.description"),
|
|
157
|
+
kind: "error"
|
|
158
|
+
});
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const usedModel = response.method === "transcription" ? response.model : response.method === "ocr" || response.method === "description" ? "preset" in model ? model.preset : model.model : void 0;
|
|
162
|
+
const derivation = {
|
|
163
|
+
from: { asset: asset.name },
|
|
164
|
+
method: response.method,
|
|
165
|
+
...usedModel ? { model: usedModel } : {},
|
|
166
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
167
|
+
inputHash: response.inputHash,
|
|
168
|
+
outputHash: "",
|
|
169
|
+
...response.output ? { output: response.output } : {}
|
|
170
|
+
};
|
|
171
|
+
const { schema } = editor;
|
|
172
|
+
const bodyNodes = body.map((block) => schema.nodeFromJSON(block));
|
|
173
|
+
const id = replaceId ?? newBlockId();
|
|
174
|
+
let node;
|
|
175
|
+
if (replaced) {
|
|
176
|
+
const chrome = Array.from({ length: 3 }, (_, index) => replaced.node.child(index));
|
|
177
|
+
node = sealed(editor, replaced.node.type.create(replaced.node.attrs, Fragment.from([...chrome, ...bodyNodes])), derivation);
|
|
178
|
+
} else {
|
|
179
|
+
const titleKey = TITLED_METHODS.includes(response.method) ? `integrations.rendition.title.${response.method}` : null;
|
|
180
|
+
const json = compositeJSON("rendition", body);
|
|
181
|
+
const [title, ...rest] = json.content;
|
|
182
|
+
const text = titleKey ? t(titleKey) : compositeKind(kinds, "rendition").label;
|
|
183
|
+
node = sealed(editor, schema.nodeFromJSON({
|
|
184
|
+
...json,
|
|
185
|
+
attrs: {
|
|
186
|
+
...json.attrs,
|
|
187
|
+
id
|
|
188
|
+
},
|
|
189
|
+
content: [{
|
|
190
|
+
...title,
|
|
191
|
+
content: [{
|
|
192
|
+
type: "text",
|
|
193
|
+
text
|
|
194
|
+
}]
|
|
195
|
+
}, ...rest]
|
|
196
|
+
}), derivation);
|
|
197
|
+
}
|
|
198
|
+
const tr = editor.state.tr;
|
|
199
|
+
if (replaced) tr.replaceWith(replaced.pos, replaced.pos + replaced.node.nodeSize, node);
|
|
200
|
+
else {
|
|
201
|
+
let insertPos = parentPos + 1;
|
|
202
|
+
for (let index = 0; index <= currentSource.index; index++) insertPos += parent.child(index).nodeSize;
|
|
203
|
+
if (!parent.canReplace(currentSource.index + 1, currentSource.index + 1, Fragment.from(node))) {
|
|
204
|
+
notify({
|
|
205
|
+
title: t("integrations.rendition.notAccepted"),
|
|
206
|
+
kind: "error"
|
|
207
|
+
});
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
tr.insert(insertPos, node);
|
|
211
|
+
}
|
|
212
|
+
const { bib } = response;
|
|
213
|
+
const workTitle = bib?.title?.trim();
|
|
214
|
+
if (workTitle && !parent.child(0).textContent.trim()) tr.insert(parentPos + 2, schema.text(workTitle));
|
|
215
|
+
if (bib && bibOf(parent) === null) {
|
|
216
|
+
const csl = { ...bib };
|
|
217
|
+
delete csl.title;
|
|
218
|
+
tr.setNodeMarkup(parentPos, void 0, {
|
|
219
|
+
...parent.attrs,
|
|
220
|
+
meta: {
|
|
221
|
+
...parent.attrs.meta,
|
|
222
|
+
bib: csl
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
editor.view.dispatch(tr);
|
|
227
|
+
editor.commands.revealBlock(id);
|
|
228
|
+
notify({
|
|
229
|
+
title: t("integrations.rendition.done"),
|
|
230
|
+
kind: "success",
|
|
231
|
+
icon: "i-lucide-captions"
|
|
232
|
+
});
|
|
233
|
+
if (response.warnings.length) notify({
|
|
234
|
+
title: t("integrations.rendition.warnings.title"),
|
|
235
|
+
description: response.warnings.map((code) => WARNING_KEYS[code] ? t(WARNING_KEYS[code]) : code).join(" "),
|
|
236
|
+
kind: "info"
|
|
237
|
+
});
|
|
238
|
+
} catch (err) {
|
|
239
|
+
if (controller.signal.aborted || editor.isDestroyed) return;
|
|
240
|
+
if (isRateLimited(err)) notifyAiRateLimited(notify, t);
|
|
241
|
+
else notify({
|
|
242
|
+
title: t("integrations.rendition.failed"),
|
|
243
|
+
description: fetchErrorMessage(err),
|
|
244
|
+
kind: "error"
|
|
245
|
+
});
|
|
246
|
+
} finally {
|
|
247
|
+
notify.dismiss?.(toastId);
|
|
248
|
+
editor.off("destroy", abort);
|
|
249
|
+
releaseRanges(editor, [anchor]);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Whether „Lesefassung erzeugen“ applies to `node`: a Baustein of a source-holding kind whose source block was
|
|
254
|
+
* found. A recording needs speech-to-text (`transcription`: the app's public configuration enables it); everything else
|
|
255
|
+
* is extracted by the server.
|
|
256
|
+
*/
|
|
257
|
+
function canCreateRendition(editor, node, transcription) {
|
|
258
|
+
const source = sourceOf(node, compositeKindsOf(editor));
|
|
259
|
+
if (!source) return false;
|
|
260
|
+
return transcription || source.node.type.name !== "audio" && source.node.type.name !== "video";
|
|
261
|
+
}
|
|
262
|
+
/** The source-holding Baustein around the asset-derived rendition at `pos`; null for anything else. */
|
|
263
|
+
function renditionParentOf(editor, pos) {
|
|
264
|
+
const node = editor.state.doc.nodeAt(pos);
|
|
265
|
+
const derivation = node && derivationOf(node);
|
|
266
|
+
if (!derivation || !("asset" in derivation.from)) return null;
|
|
267
|
+
const $pos = editor.state.doc.resolve(pos);
|
|
268
|
+
if ($pos.depth === 0 || $pos.parent.type.name !== "composite" || !sourceOf($pos.parent, compositeKindsOf(editor))) return null;
|
|
269
|
+
return {
|
|
270
|
+
node: $pos.parent,
|
|
271
|
+
pos: $pos.before()
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
/** Whether „Neu erzeugen (ersetzen)“ applies to the Baustein `node` at `pos`: an asset-derived rendition inside a Baustein that still has a source. */
|
|
275
|
+
function canRegenerateRendition(editor, node, pos, transcription) {
|
|
276
|
+
const parent = node.type.name === "composite" ? renditionParentOf(editor, pos) : null;
|
|
277
|
+
return parent !== null && canCreateRendition(editor, parent.node, transcription);
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* „Neu erzeugen (ersetzen)“: makes the rendition at `pos` again from the source of its Baustein and replaces it in place
|
|
281
|
+
* (`createRendition` with `replace`; the block id stays, so references keep resolving). A rendition whose body was
|
|
282
|
+
* edited since it was made is not replaced silently: a warning notice offers „Trotzdem ersetzen“, dismissing the notice
|
|
283
|
+
* cancels. The rendition is found again by its id when the button is pressed.
|
|
284
|
+
*/
|
|
285
|
+
function regenerateRendition(editor, pos, ai, modelRef, notify, t) {
|
|
286
|
+
const node = editor.state.doc.nodeAt(pos);
|
|
287
|
+
const id = node && blockIdOf(node);
|
|
288
|
+
const parent = renditionParentOf(editor, pos);
|
|
289
|
+
if (!node || !id || !parent) return;
|
|
290
|
+
const replace = () => {
|
|
291
|
+
const found = findBlockById(editor.state.doc, id);
|
|
292
|
+
const current = found && renditionParentOf(editor, found.pos);
|
|
293
|
+
if (found && current) createRendition(editor, current.pos, ai, modelRef, notify, t, { replace: { pos: found.pos } });
|
|
294
|
+
};
|
|
295
|
+
const kinds = compositeKindsOf(editor);
|
|
296
|
+
if (derivationState(parent.node, node, () => sha256Hex(bodyMarkdown(editor, node)), kinds).edited !== true) {
|
|
297
|
+
replace();
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
notify({
|
|
301
|
+
id: `rendition-edited-${id}`,
|
|
302
|
+
title: t("integrations.rendition.editedWarning.title"),
|
|
303
|
+
description: t("integrations.rendition.editedWarning.description"),
|
|
304
|
+
kind: "warning",
|
|
305
|
+
action: {
|
|
306
|
+
label: t("integrations.rendition.editedWarning.confirm"),
|
|
307
|
+
onClick: replace
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
//#endregion
|
|
312
|
+
export { canCreateRendition, canRegenerateRendition, createRendition, regenerateRendition };
|
|
313
|
+
|
|
314
|
+
//# sourceMappingURL=rendition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rendition.js","names":[],"sources":["../../../src/integrations/composite-ai/rendition.ts"],"sourcesContent":["import type { Editor, JSONContent } from '@tiptap/core'\nimport { Fragment, type Node as PMNode } from '@tiptap/pm/model'\nimport type { EditorBackend } from '../../core/backend'\nimport type { ExtractResponse } from '../../core/backend-types'\nimport { captureRange, fetchErrorMessage, parseBlocks, releaseRanges, resolveRange, sha256Hex, structureBlocks } from '../../core'\nimport type { MessageKey, Translate } from '../../i18n'\nimport type { Notifier } from '../../core/notify'\nimport { blockIdOf, findBlockById, newBlockId } from '../../core/schema'\nimport { isRateLimited, type ModelRef, notifyAiRateLimited } from '../../features/ai'\nimport {\n bibOf,\n bodyMarkdown,\n COMPOSITE_CHROME_COUNT,\n compositeJSON,\n compositeKind,\n compositeKindsOf,\n DERIVATION_KEY,\n derivationOf,\n derivationState,\n type Derivation,\n kindAccepts,\n sourceOf,\n} from '../../features/composites/schema'\n\nexport interface RenditionOptions {\n /**\n * Replace the rendition at this position (a child of the source-holding Baustein) in place instead of adding a new one\n * after the source: its chrome (title, description, tags) and block id stay, body and derivation are new.\n */\n replace?: { pos: number }\n}\n\n/** Methods with their own title of a fresh rendition (`integrations.rendition.title.<method>`). */\nconst TITLED_METHODS: readonly string[] = ['transcription', 'pdf-text', 'ocr', 'description']\n\n/** What the server's `warnings` codes say; an unknown code is shown as it is. */\nconst WARNING_KEYS: Readonly<Record<string, MessageKey>> = {\n 'ocr-unavailable': 'integrations.rendition.warning.ocr-unavailable',\n 'crossref-unavailable': 'integrations.rendition.warning.crossref-unavailable',\n 'pages-truncated': 'integrations.rendition.warning.pages-truncated',\n 'ocr-truncated': 'integrations.rendition.warning.ocr-truncated',\n 'bibliography-failed': 'integrations.rendition.warning.bibliography-failed',\n}\n\n/** The `<!-- page N -->` line the server puts at the start of every PDF page after the first (`joinPages`). */\nconst PAGE_MARKER = /^<!-- page (\\d+) -->[ \\t]*$/gm\n\n/**\n * `markdown` with every page marker line replaced by an emphasised page label paragraph (`*S. 2*`): parsed as it is, a\n * marker is an HTML comment and would leave an empty paragraph without the page. The stored raw output keeps the markers.\n */\nfunction withPageLabels(markdown: string, t: Translate): string {\n return markdown.replace(PAGE_MARKER, (_marker, page: string) => `*${t('integrations.rendition.page', { n: page })}*`)\n}\n\n/**\n * The body blocks of a rendition: one `transcriptSegment` per timed segment (speaker empty, `start`/`end` in seconds)\n * when the editor has the transcript feature, else the Markdown parsed and brought into the preferred structure\n * (chapters become nested `section` Bausteine in composite structure; PDF page breaks become page label paragraphs).\n */\nfunction renditionBody(editor: Editor, response: ExtractResponse, t: Translate): JSONContent[] {\n if (editor.schema.nodes.transcriptSegment && response.segments?.length) {\n const segments = response.segments\n .filter(segment => segment.text.trim())\n .map((segment): JSONContent => ({\n type: 'transcriptSegment',\n attrs: { speaker: '', start: segment.start, end: segment.end },\n content: [{ type: 'text', text: segment.text.trim() }],\n }))\n if (segments.length) return segments\n }\n return response.markdown.trim() ? structureBlocks(editor, parseBlocks(editor, withPageLabels(response.markdown, t)).blocks) : []\n}\n\n/** `node` with `derivation` in its meta, `outputHash` being the hash of the Markdown of its body (what `derivationState` compares later). */\nfunction sealed(editor: Editor, node: PMNode, derivation: Derivation): PMNode {\n const outputHash = sha256Hex(bodyMarkdown(editor, node))\n return node.type.create({ ...node.attrs, meta: { ...node.attrs.meta, [DERIVATION_KEY]: { ...derivation, outputHash } } }, node.content, node.marks)\n}\n\n/**\n * „Lesefassung erzeugen“: extracts the readable content of the source of the Baustein at `pos` (`ai.extract`, method\n * `auto`: transcript with timestamps for audio/video, full text or OCR for a PDF, a description for an image) and adds\n * it as a `rendition` Baustein right after the source block, carrying `meta.derivation` (asset, method, model, hashes,\n * the stored raw output). Bibliographic data the server found fills an empty `meta.bib` of the Baustein, and the work's\n * title an empty Baustein title. With `options.replace` the existing rendition is replaced in place (same block id).\n * The Baustein is anchored through its description when the request starts and found again after it ends, so edits\n * while it runs do not misplace the result. Notices go through `notify`, in the language of `t`; the progress notice\n * stays until the request ends.\n */\nexport async function createRendition(editor: Editor, pos: number, ai: NonNullable<EditorBackend['ai']>, modelRef: (slot: 'generate') => ModelRef, notify: Notifier, t: Translate, options: RenditionOptions = {}): Promise<void> {\n const kinds = compositeKindsOf(editor)\n const composite = editor.state.doc.nodeAt(pos)\n const source = composite && sourceOf(composite, kinds)\n if (composite?.type.name !== 'composite' || !source) return\n const asset = source.asset\n if (!asset) {\n notify({ title: t('integrations.rendition.noSource'), kind: 'error' })\n return\n }\n if (!kindAccepts(kinds, String(composite.attrs.kind), 'rendition')) {\n notify({ title: t('integrations.rendition.notAccepted'), kind: 'error' })\n return\n }\n\n let replaceId: string | null = null\n if (options.replace) {\n const target = editor.state.doc.nodeAt(options.replace.pos)\n replaceId = target && options.replace.pos > pos && options.replace.pos < pos + composite.nodeSize ? blockIdOf(target) : null\n if (target?.type.name !== 'composite' || !replaceId) return\n }\n\n const descriptionPos = pos + 1 + composite.child(0).nodeSize\n const anchor = captureRange(editor, { from: descriptionPos + 1, to: descriptionPos + 1 + composite.child(1).content.size })\n const toastId = `rendition-${blockIdOf(composite) ?? asset.name}`\n const wantsBibliography = compositeKind(kinds, String(composite.attrs.kind)).fields.some(field => field.type === 'bibliography')\n const model = modelRef('generate')\n\n const controller = new AbortController()\n const abort = () => controller.abort()\n editor.on('destroy', abort)\n notify({ id: toastId, title: t('integrations.rendition.running'), kind: 'info', icon: 'i-lucide-loader-circle', duration: 0 })\n try {\n const response = await ai.extract({ documentId: asset.documentId, name: asset.name, method: 'auto', model, bibliography: wantsBibliography }, controller.signal)\n if (editor.isDestroyed) return\n const body = renditionBody(editor, response, t)\n if (!body.length) {\n notify({ title: t('integrations.rendition.empty.title'), description: t('integrations.rendition.empty.description'), kind: 'error' })\n return\n }\n\n // The Baustein, found again through its anchored description; its source may have changed meanwhile.\n const range = resolveRange(editor.state, anchor)\n const $from = range && editor.state.doc.resolve(range.from)\n const parentPos = $from && $from.parent.type.name === 'compositeDescription' ? $from.before($from.depth - 1) : null\n const parent = parentPos === null ? null : editor.state.doc.nodeAt(parentPos)\n const currentSource = parent && sourceOf(parent, kinds)\n const replaced = replaceId ? findBlockById(editor.state.doc, replaceId) : null\n if (parentPos === null || !parent || !currentSource || (replaceId !== null && (!replaced || replaced.pos <= parentPos || replaced.pos >= parentPos + parent.nodeSize))) {\n notify({ title: t('integrations.rendition.gone.title'), description: t('integrations.rendition.gone.description'), kind: 'error' })\n return\n }\n\n // The model that wrote the content: the speech-to-text model for a transcription, the chat model for OCR and an\n // image description, none for the PDF text layer.\n const usedModel = response.method === 'transcription' ? response.model : response.method === 'ocr' || response.method === 'description' ? ('preset' in model ? model.preset : model.model) : undefined\n const derivation: Derivation = {\n from: { asset: asset.name },\n method: response.method,\n ...(usedModel ? { model: usedModel } : {}),\n createdAt: new Date().toISOString(),\n inputHash: response.inputHash,\n outputHash: '',\n ...(response.output ? { output: response.output } : {}),\n }\n const { schema } = editor\n const bodyNodes = body.map(block => schema.nodeFromJSON(block))\n const id = replaceId ?? newBlockId()\n let node: PMNode\n if (replaced) {\n const chrome = Array.from({ length: COMPOSITE_CHROME_COUNT }, (_, index) => replaced.node.child(index))\n node = sealed(editor, replaced.node.type.create(replaced.node.attrs, Fragment.from([...chrome, ...bodyNodes])), derivation)\n }\n else {\n const titleKey = TITLED_METHODS.includes(response.method) ? `integrations.rendition.title.${response.method}` as MessageKey : null\n const json = compositeJSON('rendition', body)\n const [title, ...rest] = json.content!\n const text = titleKey ? t(titleKey) : compositeKind(kinds, 'rendition').label\n const fresh = schema.nodeFromJSON({ ...json, attrs: { ...json.attrs, id }, content: [{ ...title!, content: [{ type: 'text', text }] }, ...rest] })\n node = sealed(editor, fresh, derivation)\n }\n\n const tr = editor.state.tr\n if (replaced) tr.replaceWith(replaced.pos, replaced.pos + replaced.node.nodeSize, node)\n else {\n let insertPos = parentPos + 1\n for (let index = 0; index <= currentSource.index; index++) insertPos += parent.child(index).nodeSize\n if (!parent.canReplace(currentSource.index + 1, currentSource.index + 1, Fragment.from(node))) {\n notify({ title: t('integrations.rendition.notAccepted'), kind: 'error' })\n return\n }\n tr.insert(insertPos, node)\n }\n // Bibliographic data fills only what is empty; the title is never part of `meta.bib`.\n const { bib } = response\n const workTitle = bib?.title?.trim()\n if (workTitle && !parent.child(0).textContent.trim()) tr.insert(parentPos + 2, schema.text(workTitle))\n if (bib && bibOf(parent) === null) {\n const csl = { ...bib }\n delete csl.title\n tr.setNodeMarkup(parentPos, undefined, { ...parent.attrs, meta: { ...parent.attrs.meta, bib: csl } })\n }\n editor.view.dispatch(tr)\n editor.commands.revealBlock(id)\n notify({ title: t('integrations.rendition.done'), kind: 'success', icon: 'i-lucide-captions' })\n if (response.warnings.length) {\n notify({\n title: t('integrations.rendition.warnings.title'),\n description: response.warnings.map(code => (WARNING_KEYS[code] ? t(WARNING_KEYS[code]) : code)).join(' '),\n kind: 'info',\n })\n }\n }\n catch (err) {\n if (controller.signal.aborted || editor.isDestroyed) return\n if (isRateLimited(err)) notifyAiRateLimited(notify, t)\n else notify({ title: t('integrations.rendition.failed'), description: fetchErrorMessage(err), kind: 'error' })\n }\n finally {\n notify.dismiss?.(toastId)\n editor.off('destroy', abort)\n releaseRanges(editor, [anchor])\n }\n}\n\n/**\n * Whether „Lesefassung erzeugen“ applies to `node`: a Baustein of a source-holding kind whose source block was\n * found. A recording needs speech-to-text (`transcription`: the app's public configuration enables it); everything else\n * is extracted by the server.\n */\nexport function canCreateRendition(editor: Editor, node: PMNode, transcription: boolean): boolean {\n const source = sourceOf(node, compositeKindsOf(editor))\n if (!source) return false\n return transcription || (source.node.type.name !== 'audio' && source.node.type.name !== 'video')\n}\n\n/** The source-holding Baustein around the asset-derived rendition at `pos`; null for anything else. */\nfunction renditionParentOf(editor: Editor, pos: number): { node: PMNode, pos: number } | null {\n const node = editor.state.doc.nodeAt(pos)\n const derivation = node && derivationOf(node)\n if (!derivation || !('asset' in derivation.from)) return null\n const $pos = editor.state.doc.resolve(pos)\n if ($pos.depth === 0 || $pos.parent.type.name !== 'composite' || !sourceOf($pos.parent, compositeKindsOf(editor))) return null\n return { node: $pos.parent, pos: $pos.before() }\n}\n\n/** Whether „Neu erzeugen (ersetzen)“ applies to the Baustein `node` at `pos`: an asset-derived rendition inside a Baustein that still has a source. */\nexport function canRegenerateRendition(editor: Editor, node: PMNode, pos: number, transcription: boolean): boolean {\n const parent = node.type.name === 'composite' ? renditionParentOf(editor, pos) : null\n return parent !== null && canCreateRendition(editor, parent.node, transcription)\n}\n\n/**\n * „Neu erzeugen (ersetzen)“: makes the rendition at `pos` again from the source of its Baustein and replaces it in place\n * (`createRendition` with `replace`; the block id stays, so references keep resolving). A rendition whose body was\n * edited since it was made is not replaced silently: a warning notice offers „Trotzdem ersetzen“, dismissing the notice\n * cancels. The rendition is found again by its id when the button is pressed.\n */\nexport function regenerateRendition(editor: Editor, pos: number, ai: NonNullable<EditorBackend['ai']>, modelRef: (slot: 'generate') => ModelRef, notify: Notifier, t: Translate): void {\n const node = editor.state.doc.nodeAt(pos)\n const id = node && blockIdOf(node)\n const parent = renditionParentOf(editor, pos)\n if (!node || !id || !parent) return\n\n const replace = () => {\n const found = findBlockById(editor.state.doc, id)\n const current = found && renditionParentOf(editor, found.pos)\n if (found && current) void createRendition(editor, current.pos, ai, modelRef, notify, t, { replace: { pos: found.pos } })\n }\n const kinds = compositeKindsOf(editor)\n if (derivationState(parent.node, node, () => sha256Hex(bodyMarkdown(editor, node)), kinds).edited !== true) {\n replace()\n return\n }\n notify({\n id: `rendition-edited-${id}`,\n title: t('integrations.rendition.editedWarning.title'),\n description: t('integrations.rendition.editedWarning.description'),\n kind: 'warning',\n action: { label: t('integrations.rendition.editedWarning.confirm'), onClick: replace },\n })\n}\n"],"mappings":"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"}
|
|
@@ -5,11 +5,13 @@ import "../../core/index.js";
|
|
|
5
5
|
* File import into composites. Needs the `composites` and `media` features; neither imports this one.
|
|
6
6
|
*
|
|
7
7
|
* - **Wrapping:** the `wrapImport` stage puts the blocks of every imported file (parsed text or Markdown, or the
|
|
8
|
-
* uploaded media or file block; drop, paste, picker and recorder alike) into one
|
|
9
|
-
* file's name stem and carrying its filename, type, size and import date as meta.
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
8
|
+
* uploaded media or file block; drop, paste, picker and recorder alike) into one composite titled with the
|
|
9
|
+
* file's name stem and carrying its filename, type, size and import date as meta. The kind follows the MIME type:
|
|
10
|
+
* audio and video become a `recording`, images a `figure`, everything else (PDFs, office files, text) a `document`.
|
|
11
|
+
* Without this feature the blocks are inserted as they are.
|
|
12
|
+
* - **Actions:** the `/` command „Datei importieren“ (`datei`, ability `composite`) picks any files and imports them
|
|
13
|
+
* through `editor.storage.media.importFiles` at the caret; the block action „Quelle ersetzen“ (`source-replace`, on
|
|
14
|
+
* composites with a source block) uploads a new file into the existing source block, keeping its id.
|
|
13
15
|
*
|
|
14
16
|
* Install it anywhere after `composites` and `media`; the `/` entry follows the order of the feature list. Framework-free
|
|
15
17
|
* (`EditorFeature<never>`: no component slots), so one instance serves the Vue and the React surface.
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { ABILITY } from "../../core/schema/abilities.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { blockIdOf, findBlockById } from "../../core/schema/block-ids.js";
|
|
3
|
+
import { fetchErrorMessage } from "../../core/fetch-error.js";
|
|
4
|
+
import { sourceOf } from "../../features/composites/derivation.js";
|
|
5
|
+
import { compositeJSON, compositeKindsOf } from "../../features/composites/nodes.js";
|
|
6
|
+
import { acceptFor, mediaKindOf, mediaMime } from "../../features/media/schema.js";
|
|
4
7
|
import { pickFiles } from "../../features/media/upload.js";
|
|
5
8
|
import { isTextFile } from "../../features/media/file-import.js";
|
|
6
9
|
//#region src/integrations/composite-media/index.ts
|
|
@@ -9,15 +12,21 @@ function stemOf(name) {
|
|
|
9
12
|
const dot = name.lastIndexOf(".");
|
|
10
13
|
return dot > 0 ? name.slice(0, dot) : name;
|
|
11
14
|
}
|
|
12
|
-
/**
|
|
13
|
-
function
|
|
14
|
-
const
|
|
15
|
+
/** The kind an imported `file` becomes: audio and video a `recording`, an image a `figure`, anything else (PDFs, office files, text) a `document`. */
|
|
16
|
+
function importKindOf(editor, file, text) {
|
|
17
|
+
const kind = text ? null : mediaKindOf(file.type);
|
|
18
|
+
const id = kind === "audio" || kind === "video" ? "recording" : kind === "image" ? "figure" : "document";
|
|
19
|
+
return compositeKindsOf(editor).some((k) => k.id === id) ? id : "document";
|
|
20
|
+
}
|
|
21
|
+
/** A composite of kind `kind` titled with the stem of `file`'s name, holding its original name, type, size and import date. */
|
|
22
|
+
function documentComposite(kind, file, text, body) {
|
|
23
|
+
const composite = compositeJSON(kind, body);
|
|
15
24
|
const [title, ...rest] = composite.content;
|
|
16
25
|
const stem = stemOf(file.name);
|
|
17
26
|
return {
|
|
18
27
|
...composite,
|
|
19
28
|
attrs: {
|
|
20
|
-
kind
|
|
29
|
+
kind,
|
|
21
30
|
meta: {
|
|
22
31
|
filename: file.name,
|
|
23
32
|
mimeType: mediaMime(file.type) || (text ? "text/markdown" : "application/octet-stream"),
|
|
@@ -35,14 +44,75 @@ function documentComposite(file, text, body) {
|
|
|
35
44
|
};
|
|
36
45
|
}
|
|
37
46
|
/**
|
|
47
|
+
* Swaps the source file of `composite` in place: picks a file of the source block's media type, uploads it and rewrites
|
|
48
|
+
* `src`, `hash`, `mimeType`, `title` and `size` of the existing source block (those of them its node type has). The
|
|
49
|
+
* block keeps its attributes otherwise, its id included, and so do the composite and every reference to either.
|
|
50
|
+
*/
|
|
51
|
+
async function replaceSource(editor, composite, ctx) {
|
|
52
|
+
const source = sourceOf(composite, compositeKindsOf(editor));
|
|
53
|
+
const sourceId = source && blockIdOf(source.node);
|
|
54
|
+
if (!source || !sourceId) return;
|
|
55
|
+
const type = source.node.type.name;
|
|
56
|
+
const [file] = await pickFiles(acceptFor(type), false);
|
|
57
|
+
if (!file || editor.isDestroyed) return;
|
|
58
|
+
try {
|
|
59
|
+
if ((mediaKindOf(file.type) ?? "file") !== type) throw new Error(`${file.type || file.name}: ${type}`);
|
|
60
|
+
const { url, sha256 } = await editor.storage.media.upload(file);
|
|
61
|
+
if (editor.isDestroyed) return;
|
|
62
|
+
const target = findBlockById(editor.state.doc, sourceId);
|
|
63
|
+
if (!target) {
|
|
64
|
+
ctx.notify({
|
|
65
|
+
title: ctx.t("integrations.sourceReplace.gone"),
|
|
66
|
+
kind: "error"
|
|
67
|
+
});
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const next = {
|
|
71
|
+
src: url,
|
|
72
|
+
hash: sha256 ?? null,
|
|
73
|
+
mimeType: mediaMime(file.type) || "application/octet-stream",
|
|
74
|
+
title: file.name,
|
|
75
|
+
size: file.size
|
|
76
|
+
};
|
|
77
|
+
const attrs = { ...target.node.attrs };
|
|
78
|
+
for (const [key, value] of Object.entries(next)) if (key in attrs) attrs[key] = value;
|
|
79
|
+
editor.view.dispatch(editor.state.tr.setNodeMarkup(target.pos, void 0, attrs));
|
|
80
|
+
ctx.notify({
|
|
81
|
+
title: ctx.t("integrations.sourceReplace.done"),
|
|
82
|
+
kind: "success"
|
|
83
|
+
});
|
|
84
|
+
} catch (error) {
|
|
85
|
+
ctx.notify({
|
|
86
|
+
title: ctx.t("integrations.sourceReplace.failed"),
|
|
87
|
+
description: fetchErrorMessage(error),
|
|
88
|
+
kind: "error"
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function sourceActions(ctx) {
|
|
93
|
+
return [{
|
|
94
|
+
id: "source-replace",
|
|
95
|
+
label: ctx.t("integrations.sourceReplace.action"),
|
|
96
|
+
icon: "i-lucide-file-input",
|
|
97
|
+
ability: ABILITY.media,
|
|
98
|
+
order: 420,
|
|
99
|
+
isVisible: ({ editor, node }) => node.type.name === "composite" && sourceOf(node, compositeKindsOf(editor)) !== null,
|
|
100
|
+
run: ({ editor, node }) => {
|
|
101
|
+
replaceSource(editor, node, ctx);
|
|
102
|
+
}
|
|
103
|
+
}];
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
38
106
|
* File import into composites. Needs the `composites` and `media` features; neither imports this one.
|
|
39
107
|
*
|
|
40
108
|
* - **Wrapping:** the `wrapImport` stage puts the blocks of every imported file (parsed text or Markdown, or the
|
|
41
|
-
* uploaded media or file block; drop, paste, picker and recorder alike) into one
|
|
42
|
-
* file's name stem and carrying its filename, type, size and import date as meta.
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
109
|
+
* uploaded media or file block; drop, paste, picker and recorder alike) into one composite titled with the
|
|
110
|
+
* file's name stem and carrying its filename, type, size and import date as meta. The kind follows the MIME type:
|
|
111
|
+
* audio and video become a `recording`, images a `figure`, everything else (PDFs, office files, text) a `document`.
|
|
112
|
+
* Without this feature the blocks are inserted as they are.
|
|
113
|
+
* - **Actions:** the `/` command „Datei importieren“ (`datei`, ability `composite`) picks any files and imports them
|
|
114
|
+
* through `editor.storage.media.importFiles` at the caret; the block action „Quelle ersetzen“ (`source-replace`, on
|
|
115
|
+
* composites with a source block) uploads a new file into the existing source block, keeping its id.
|
|
46
116
|
*
|
|
47
117
|
* Install it anywhere after `composites` and `media`; the `/` entry follows the order of the feature list. Framework-free
|
|
48
118
|
* (`EditorFeature<never>`: no component slots), so one instance serves the Vue and the React surface.
|
|
@@ -50,10 +120,13 @@ function documentComposite(file, text, body) {
|
|
|
50
120
|
function compositeMediaFeature() {
|
|
51
121
|
return {
|
|
52
122
|
id: "composite-media",
|
|
123
|
+
dimension: "content",
|
|
53
124
|
requires: ["composites", "media"],
|
|
54
|
-
blocks: { wrapImport: (
|
|
55
|
-
|
|
125
|
+
blocks: { wrapImport: (editor, file, blocks) => [documentComposite(importKindOf(editor, file, isTextFile(file)), file, isTextFile(file), blocks)] },
|
|
126
|
+
blockActions: sourceActions,
|
|
127
|
+
commands: (ctx) => [{
|
|
56
128
|
id: "datei",
|
|
129
|
+
slash: {},
|
|
57
130
|
label: ctx.t("integrations.compositeMedia.import"),
|
|
58
131
|
icon: "i-lucide-file-up",
|
|
59
132
|
ability: ABILITY.composite,
|